异步/等待隐式返回承诺?

新手上路,请多包涵

我读到由 async 关键字标记的异步函数隐式返回一个承诺:

 async function getVal(){
 return await doSomethingAync();
}

var ret = getVal();
console.log(ret);

但这不连贯……假设 doSomethingAsync() 返回一个承诺,并且 await 关键字将返回承诺的值,而不是承诺本身,那么我的 getVal 函数 应该 返回该值,而不是隐含的承诺.

那么到底是怎么回事呢?由 async 关键字标记的函数是隐式返回 promises 还是我们控制它们返回的内容?

也许如果我们没有明确地返回某些东西,那么他们会隐式地返回一个承诺……?

更清楚地说,上面和之间有区别

function doSomethingAync(charlie) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(charlie || 'yikes');
        }, 100);
    })
}

async function getVal(){
   var val = await doSomethingAync();  // val is not a promise
   console.log(val); // logs 'yikes' or whatever
   return val;  // but this returns a promise
}

var ret = getVal();
console.log(ret);  //logs a promise

在我的概要中,这种行为确实与传统的返回语句不一致。似乎当您从 async 函数显式返回非承诺值时,它会强制将其包装在承诺中。我对它没有什么大问题,但它确实违背了普通的 JS。

原文由 Alexander Mills 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 528
2 个回答

返回值永远是一个承诺。如果您没有显式返回一个承诺,您返回的值将自动包装在一个承诺中。

 async function increment(num) {
  return num + 1;
}

// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));

就算有去无回也一样! (返回 Promise { undefined }

 async function increment(num) {}

即使有 await

 function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function incrementTwice(num) {
  const numPlus1 = await defer(() => num + 1);
  return numPlus1 + 1;
}

// Logs: 5
incrementTwice(3).then(num => console.log(num));

Promises auto-unwrap,因此,如果您确实从 async 函数中返回一个值的 promise,您将收到该值的 promise(不是对该值的 promise 的 promise)。

 function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function increment(num) {
  // It doesn't matter whether you put an `await` here.
  return defer(() => num + 1);
}

// Logs: 4
increment(3).then(num => console.log(num));


在我的概要中,这种行为确实与传统的返回语句不一致。似乎当您从异步函数显式返回非承诺值时,它会强制将其包装在承诺中。我对它没有什么大问题,但它确实违背了普通的 JS。

ES6 的函数不会返回与 return 完全相同的值。这些函数称为生成器。

 function* foo() {
  return 'test';
}

// Logs an object.
console.log(foo());

// Logs 'test'.
console.log(foo().next().value);

原文由 Nathan Wall 发布,翻译遵循 CC BY-SA 4.0 许可协议

是的,异步函数总是会返回一个承诺。

根据 tc39 规范,一个 async function 脱糖到生成器,生成 Promise s。

具体来说:

 async function <name>?<argumentlist><body>

脱糖:

 function <name>?<argumentlist>{ return spawn(function*() <body>, this); }

其中 spawn “是对以下算法的调用”:

 function spawn(genF, self) {
    return new Promise(function(resolve, reject) {
        var gen = genF.call(self);
        function step(nextF) {
            var next;
            try {
                next = nextF();
            } catch(e) {
                // finished with failure, reject the promise
                reject(e);
                return;
            }
            if(next.done) {
                // finished with success, resolve the promise
                resolve(next.value);
                return;
            }
            // not finished, chain off the yielded promise and `step` again
            Promise.resolve(next.value).then(function(v) {
                step(function() { return gen.next(v); });
            }, function(e) {
                step(function() { return gen.throw(e); });
            });
        }
        step(function() { return gen.next(undefined); });
    });
}

原文由 Jon Surrell 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题