简体   繁体   English

JS 承诺里面的承诺

[英]JS promise inside promise

The getLocation() function that should retrieve location in 3 attempts returns undefined instead.应该在 3 次尝试中检索位置的getLocation()函数返回undefined navigator.geolocation.getCurrentPosition() returns the correct position, but the problem is in the promise handling. navigator.geolocation.getCurrentPosition()返回正确的位置,但问题在于承诺处理。

The problem is apparently that I am calling a promise inside promise.问题显然是我在承诺中调用了一个承诺。 I am not allowed to use the await keyword inside geolocate() already declared as async .我不允许在已经声明为async geolocate()使用await关键字。

Original call:原始调用:

var getLocationPromise = this.getLocation();
// Do something...
location = await getLocationPromise;

getLocation() : getLocation()

  async getLocation() {
    return new Promise((resolve, reject) => {
      var geolocate;
      for (let i=0; i<3; i++) {

        geolocate = this.geolocate();

        try {
            var location = geolocate;//CAN'T USE AWAIT INSIDE ASYNC...
            resolve(location);
        } catch(err) {
            continue;
        }
      } 
      reject("Max geolocation attempts");
    });
  }

geolocate() : geolocate()

  async geolocate() {
    return new Promise((resolve, reject) => {

      navigator.geolocation.getCurrentPosition(
        (position) => {
          resolve(position);
        },
        (err) => {
          reject(err);
        },
        {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
      );
    });
  }

As long as the following is in a function declared async只要以下内容在声明为 async 的函数中

var getLocationPromise = this.getLocation();
// Do something...
location = await getLocationPromise;

it should be fine as is应该没问题

looking at getLocation/geolocate, unless you need a separate geolocate method, they should be able to be combined and simplified to查看 getLocation/geolocate,除非您需要单独的 geolocate 方法,否则它们应该能够组合并简化为

getLocation() {
    var geolocate = () =>
        new Promise((resolve, reject) => 
            navigator.geolocation.getCurrentPosition(resolve, reject, {
                enableHighAccuracy: true,
                timeout: 20000,
                maximumAge: 1000
            });
        );
    // this function will "retry" the supplied function (fn) cont times
    var limitedPromiseRetry = (fn, cont) => fn().catch(err => cont > 0 ? limitedPromiseRetry(fn, cont-1) : Promise.reject('Max number of geolocation attempts'));
    return limitedPromiseRetry(geolocate, 3);
}

async and await异步和等待

You can not use await inside functions without the async keyword.如果没有async关键字,就不能在函数内部使用await So the error occurs because the executor function is not async :所以发生错误是因为 executor 函数不是async

var getLocation = async function(){ // <-- this function has "async" keyword, but ...
    return new Promise( function( resolve, reject ){ // <-- ... this "executor" function has no "async" keyword.
        var value = await geolocate();               // <-- ERROR: await is only valid in async function.
        resolve( value );
    })
};

But you should not make the promise executor an async function.但是你不应该让 promise executor 成为async函数。
See https://eslint.org/docs/rules/no-async-promise-executor for more info.有关更多信息,请参阅https://eslint.org/docs/rules/no-async-promise-executor

new Promise( async function( resolve, reject ){ // <-- BAD ! Don't do it !
   ...
})

without nested promise没有嵌套的承诺

But as getLocation is a promise already, you do not need the nested new Promise( ... ) at all:但由于getLocation已经是一个承诺,你根本不需要嵌套的new Promise( ... )

var getLocation = async function(){ // <-- "async" makes a function to be a promise
    var value = await geolocate();

    // "return value" inside async function is "the same" as
    // "resolve( value )" in a promise
    return value;
};

So, theoretically, you could solve your problem in the following way (although there are probably better ways of doing it. For 'rejecting' inside async function, see also How to reject in async/await syntax? ).因此,理论上,您可以通过以下方式解决您的问题(尽管可能有更好的方法。对于异步函数中的“拒绝”,另请参阅如何在 async/await 语法中拒绝? )。

var getLocation = async function(){
    for( let i = 0; i < 3; i++ ){
        try {
            console.log('try ...', i);
            var location = await geolocate(i);
            console.log('... success');
            return location;
        } catch(err) {
            console.log('... next try');
            continue;
        }
    }
    return Promise.reject('no success');
};

getLocation().then(function(result){
    console.log('then:', result);
}).catch(function(reason){
    console.log('error:', reason);
})

nested Promises嵌套承诺

Promises inside promises are ok.承诺里面的承诺是可以的。
Note that resolving promises with resolved promises behaves "the same" as resolving only one promise.请注意,使用已解决的承诺解决承诺与仅解决一个承诺的行为“相同” You will not notice any difference in the .then() function, no matter if you resolve a value, or a resolved promise inside a promise, ... and so on.您不会注意到.then()函数有任何区别,无论您是解析一个值,还是在 Promise 中解析一个 promise,...等等。

var nestedPromises = new Promise( function( resolve1, reject1 ){
    resolve1( new Promise( function( resolve2, reject2 ){
        resolve2( new Promise( function( resolve3, reject3 ){
            resolve3('resolved value');
        }));
    }));
});

nestedPromises.then( function( value ){
    console.log('value:', value);   // <-- "value: resolved value"
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM