异步函数返回的是一个 Promise,而不是一个值。

31
我正在努力理解async/await与promises如何一起使用。
async function latestTime() {
  const bl = await web3.eth.getBlock('latest');
  console.log(bl.timestamp); // Returns a primitive
  console.log(typeof bl.timestamp.then == 'function'); //Returns false - not a promise
  return bl.timestamp;
}
const time = latestTime(); // Promise { <pending> }

据我理解,await应该是阻塞的,在上面的代码中它似乎阻塞了返回一个带有原始时间戳的对象bl。然后,我的函数返回了原始值,但是时间变量被设置为一个未决的promise而不是那个原始值。我错过了什么吗?

2
这就是异步函数的作用 - 阅读规范 - Jaromanda X
await should be blocking 不是正确的做法 - 在 JavaScript 中使用非阻塞代码是一个“坏主意”™,而 async/await 与阻塞毫无关系。 - Jaromanda X
1
每个 async function 都会返回一个 promise,这样在其中您就可以使用 await 等待其他 promises,这就是整个的重点。 - Bergi
1
这个回答解决了你的问题吗?async/await 隐式返回 Promise 吗? - Ivar
3个回答

30

异步前缀是 Promise 的一种包装器。

async function latestTime() {
    const bl = await web3.eth.getBlock('latest');
    console.log(bl.timestamp); // Returns a primitive
    console.log(typeof bl.timestamp.then == 'function'); //Returns false - not a promise
    return bl.timestamp;
}

相同于

function latestTime() {
    return new Promise(function(resolve,success){
        const bl = web3.eth.getBlock('latest');
        bl.then(function(result){
            console.log(result.timestamp); // Returns a primitive
            console.log(typeof result.timestamp.then == 'function'); //Returns false - not a promise
            resolve(result.timestamp)
        })
}

3
仅作为一点小注:那个async函数的翻译有几个问题。从广义概念上来说还可以,但它不能正确地处理拒绝(rejection)、有语法错误,并且给传递给Promise执行器(用于拒绝Promise的函数)的第二个参数命名非常令人惊讶(success?!)。 :-) - T.J. Crowder

28

async函数总是返回一个Promise。这是它报告异步工作完成的方式。如果在另一个async函数中使用它,您可以使用await来等待其Promise解决,但在非async函数中(通常在顶层或事件处理程序中),您必须直接使用Promise,例如:

latestTime()
.then(time => {
    console.log(time);
})
.catch(error => {
    // Handle/report error
});

虽然如果您在JavaScript模块的顶层执行此操作,现代环境现在都支持模块中的顶级await

const time = await latestTime();

请注意,如果该承诺被拒绝,您的模块将无法加载。如果您的模块即使承诺失败仍能有意义地工作,请确保使用try/catch来处理承诺拒绝。


以显式承诺回调术语来看,了解JavaScript引擎在幕后如何处理您的async函数,可能会对事情有所启示:

function latestTime() {
    return new Promise((resolve, reject) => {
        web3.eth.getBlock('latest')
        .then(bl => {
            console.log(bl.timestamp);
            console.log(typeof bl.timestamp.then == 'function');
            resolve(bl.timestamp);
        })
        .catch(reject);
    });
}

关于此事有一些重要注意事项:

  • 您传递给new Promise的函数(即 promise executor 函数)会被new Promise同步调用。
    • 这就是为什么开始操作时,会同步调用web3.eth.getBlock来开始工作。
  • 在 promise executor 中抛出的任何错误等都将被new Promise捕获,并转换为promise rejection。
  • 在 promise 回调中抛出的任何错误,例如我们传递给then的回调函数,都将被捕获并转换为rejection。

12
async函数将始终返回Promise。返回值将是一个“Promise”,因此在您的情况下,它将是:

async函数将始终返回Promise。返回值将是 Promise,因此在您的情况下,它将是:
async function latestTime(): Promise<some primitive> {
  const bl = await web3.eth.getBlock('latest');
  return bl.timestamp;
}
所以,你可以进一步像这样使用它的功能:
const time = await latestTime();

为了全面了解async/await功能,最好阅读文档。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接