【问题标题】:JS promise inside promiseJS 承诺里面的承诺
【发布时间】:2017-05-18 12:31:44
【问题描述】:

应该在 3 次尝试中检索位置的 getLocation() 函数改为返回 undefinednavigator.geolocation.getCurrentPosition() 返回正确的位置,但问题出在 Promise 处理中。

问题显然是我在 Promise 中调用了 Promise。我不允许在 geolocate() 中使用已声明为 asyncawait 关键字。

原来的电话:

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}
      );
    });
  }

【问题讨论】:

  • await getLocation().then(); === await getLocation(); - 不是吗?
  • 它给出了不同的结果。我对await getLocation(); 返回undefined 有问题,所以我使用await getLocation().then();,这似乎更安全
  • 不知道为什么你在geolocategetLocation 上使用async - 因为这些函数都没有使用await
  • //CAN'T USE AWAIT INSIDE ASYNC - 不,这是不对的,你只能在async中使用await
  • 这就是问题所在,不能await in async

标签: javascript geolocation promise async-await es6-promise


【解决方案1】:

只要以下是在一个声明为异步的函数中

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);
}

【讨论】:

  • 不错且紧凑的解决方案,它避免了使用双重承诺。从您的回复中,我了解到将 promise 放入 promise 不是一个好主意并且不受支持?
  • 不,支持,只是在这种情况下不需要
【解决方案2】:

异步和等待

你不能在函数中使用await 没有 async 关键字。所以报错是因为executor函数是notasync:

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;
};

因此,理论上,您可以通过以下方式解决您的问题(尽管可能有更好的方法。对于异步函数内部的“拒绝”,另请参阅How to reject in async/await syntax?)。

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);
})

嵌套承诺

Promise 中的 Promise 是可以的。
请注意,使用已解决的 Promise 解决 Promise 的行为“相同”,就像只解决一个 Promise。你不会注意到 .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"
})

【讨论】:

    猜你喜欢
    • 2015-10-06
    • 2019-07-08
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2015-02-22
    • 2016-06-13
    • 1970-01-01
    相关资源
    最近更新 更多