簡體   English   中英

等到某個條件成立?

[英]Wait until a condition is true?

我在 JavaScript 中使用navigator.geolocation.watchPosition ,我想要一種方法來處理用戶可能在watchPosition找到其位置之前提交依賴於位置的表單的可能性。

理想情況下,用戶會定期看到“等待位置”消息,直到獲得位置,然后提交表單。

但是,我不確定如何在 JavaScript 中實現這一點,因為它沒有wait function。

當前代碼:

var current_latlng = null;
function gpsSuccess(pos){
    //console.log('gpsSuccess');  
    if (pos.coords) { 
        lat = pos.coords.latitude;
        lng = pos.coords.longitude;
    }
    else {
        lat = pos.latitude;
        lng = pos.longitude;
    }
    current_latlng = new google.maps.LatLng(lat, lng);
}
watchId = navigator.geolocation.watchPosition(gpsSuccess,
                  gpsFail, {timeout:5000, maximumAge: 300000});
$('#route-form').submit(function(event) {
    // User submits form, we need their location...
    while(current_location==null) {
        toastMessage('Waiting for your location...');
        wait(500); // What should I use instead?
    }
    // Continue with location found...
});

就個人而言,我使用了一個封裝setTimeout()waitfor()函數:

//**********************************************************************
// function waitfor - Wait until a condition is met
//        
// Needed parameters:
//    test: function that returns a value
//    expectedValue: the value of the test function we are waiting for
//    msec: delay between the calls to test
//    callback: function to execute when the condition is met
// Parameters for debugging:
//    count: used to count the loops
//    source: a string to specify an ID, a message, etc
//**********************************************************************
function waitfor(test, expectedValue, msec, count, source, callback) {
    // Check if condition met. If not, re-check later (msec).
    while (test() !== expectedValue) {
        count++;
        setTimeout(function() {
            waitfor(test, expectedValue, msec, count, source, callback);
        }, msec);
        return;
    }
    // Condition finally met. callback() can be executed.
    console.log(source + ': ' + test() + ', expected: ' + expectedValue + ', ' + count + ' loops.');
    callback();
}

我用以下方式使用waitfor()函數:

var _TIMEOUT = 50; // waitfor test rate [msec]
var bBusy = true;  // Busy flag (will be changed somewhere else in the code)
...
// Test a flag
function _isBusy() {
    return bBusy;
}
...

// Wait until idle (busy must be false)
waitfor(_isBusy, false, _TIMEOUT, 0, 'play->busy false', function() {
    alert('The show can resume !');
});

這正是承諾的發明和實施(因為OP問他的問題)。

查看所有各種實現,例如promisejs.org

你會想要使用setTimeout

function checkAndSubmit(form) {
    var location = getLocation();
    if (!location) {
        setTimeout(checkAndSubmit, 500, form); // setTimeout(func, timeMS, params...)
    } else {
        // Set location on form here if it isn't in getLocation()
        form.submit();
    }
}

... getLocation查找您的位置。

您可以使用超時嘗試重新提交表單:

$('#route-form').submit(function(event) {
    // User submits form, we need their location...
    if(current_location==null) {
        toastMessage('Waiting for your location...');
        setTimeout(function(){ $('#route-form').submit(); }, 500); // Try to submit form after timeout
        return false;
    } else {
        // Continue with location found...
    }
});

使用Promise的現代解決方案

function waitFor(conditionFunction) {

  const poll = resolve => {
    if(conditionFunction()) resolve();
    else setTimeout(_ => poll(resolve), 400);
  }

  return new Promise(poll);
}

用法

waitFor(_ => flag === true)
  .then(_ => console.log('the wait is over!'));

要么

async function demo() {
  await waitFor(_ => flag === true);
  console.log('the wait is over!');
}

參考
承諾
箭頭功能
異步/等待

class App extends React.Component {

componentDidMount() {
   this.processToken();

}
 processToken = () => {
    try {
        const params = querySearch(this.props.location.search);
        if('accessToken' in params){
            this.setOrderContext(params);
            this.props.history.push(`/myinfo`);
        }
    } catch(ex) {
      console.log(ex);
    }
    }

   setOrderContext (params){
     //this action calls a reducer and put the token in session storage
     this.props.userActions.processUserToken({data: {accessToken:params.accessToken}});
}

render() {
    return (

        <Switch>
            //myinfo component needs accessToken to retrieve my info
            <Route path="/myInfo" component={InofUI.App} />
        </Switch>

    );
}

然后在InofUI.App里面

componentDidMount() {
        this.retrieveMyInfo();
    }

    retrieveMyInfo = async () => {
        await this.untilTokenIsSet();
        const { location, history } = this.props;
        this.props.processUser(location, history);
    }

    untilTokenIsSet= () => {
        const poll = (resolve) => {
            const { user } = this.props;
            const { accessToken } = user;
            console.log('getting accessToken', accessToken);
            if (accessToken) {
                resolve();
            } else {
                console.log('wating for token .. ');
                setTimeout(() => poll(resolve), 100);
            }
        };
        return new Promise(poll);
    } 

嘗試像這樣使用setIntervalclearInterval ......

var current_latlng = null;

function gpsSuccess(pos) {
    //console.log('gpsSuccess');  
    if (pos.coords) {
        lat = pos.coords.latitude;
        lng = pos.coords.longitude;
    } else {
        lat = pos.latitude;
        lng = pos.longitude;
    }
    current_latlng = new google.maps.LatLng(lat, lng);
}
watchId = navigator.geolocation.watchPosition(gpsSuccess,
    gpsFail, {
        timeout: 5000,
        maximumAge: 300000
    });
$('#route-form').submit(function (event) {
    // User submits form, we need their location...
    // Checks status every half-second
    var watch = setInterval(task, 500)

    function task() {
        if (current_latlng != null) {
            clearInterval(watch)
            watch = false
            return callback()
        } else {
            toastMessage('Waiting for your location...');

        }
    }

    function callback() {
        // Continue on with location found...
    }
});
export default (condition: Function, interval = 1000) =>
  new Promise((resolve) => {
    const runner = () => {
      const timeout = setTimeout(runner, interval);

      if (condition()) {
        clearTimeout(timeout);
        resolve(undefined);
        return;
      }
    };

    runner();
  });

這接受任何 function,即使它是異步的,並且當它評估為真值(默認情況下每四分之一秒檢查一次)時,會解析它。

function waitFor(condition, step = 250, timeout = Infinity) {
  return new Promise((resolve, reject) => {
    const now = Date.now();
    let running = false;
    const interval = setInterval(async () => {
      if (running) return;
      running = true;
      const result = await condition();
      if (result) {
        clearInterval(interval);
        resolve(result);
      } else if (Date.now() - now >= timeout * 1000) {
        clearInterval(interval);
        reject(result);
      }
      running = false;
    }, step);
  });
}

例子

 example(); async function example() { let foo = 'bar'; setTimeout(() => foo = null, 2000); console.log(`foo === "${foo}"`); await waitFor(() => foo === null); console.log('2 seconds have elapsed.'); console.log(`foo === ${foo}`); } function waitFor(condition, step = 250, timeout = Infinity) { return new Promise((resolve, reject) => { const now = Date.now(); let running = false; const interval = setInterval(async () => { if (running) return; running = true; const result = await condition(); if (result) { clearInterval(interval); resolve(result); } else if (Date.now() - now >= timeout * 1000) { clearInterval(interval); reject(result); } running = false; }, step); }); }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM