繁体   English   中英

JS 承诺里面的承诺

[英]JS promise inside promise

应该在 3 次尝试中检索位置的getLocation()函数返回undefined navigator.geolocation.getCurrentPosition()返回正确的位置,但问题在于承诺处理。

问题显然是我在承诺中调用了一个承诺。 我不允许在已经声明为async geolocate()使用await关键字。

原始调用:

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

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()

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

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

只要以下内容在声明为 async 的函数中

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

应该没问题

查看 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关键字,就不能在函数内部使用await 所以发生错误是因为 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 );
    })
};

但是你不应该让 promise executor 成为async函数。
有关更多信息,请参阅https://eslint.org/docs/rules/no-async-promise-executor

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

没有嵌套的承诺

但由于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;
};

因此,理论上,您可以通过以下方式解决您的问题(尽管可能有更好的方法。对于异步函数中的“拒绝”,另请参阅如何在 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);
})

嵌套承诺

承诺里面的承诺是可以的。
请注意,使用已解决的承诺解决承诺与仅解决一个承诺的行为“相同” 您不会注意到.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-2024 STACKOOM.COM