如何在回调中使用await?

时间:2018-08-12 03:30:42

标签: javascript node.js

我的代码是:

async function run() {
  await sleep(1);
  fs.readFile('list.txt', 'utf8', function (err, text) {
    console.log(text);
    await sleep(5);
   });
}

run();

await sleep(1)很好,但是await sleep(5)会导致:

  

SyntaxError:异步仅在异步函数中有效

fs.readFile是问题吗?在这种情况下如何使用await

上面是测试的简化示例。在我的实际用法中,我需要将await sleep放在深度嵌套在更多异步函数中的回调中。

4 个答案:

答案 0 :(得分:4)

我不确定sleep在做什么,但是您问题中的问题正在发生,因为对fs.readfile的回调不是异步函数,而await sleep(5)在哪里

async function run() {
    await sleep(1);
    fs.readFile('list.txt', 'utf8', function (err, text) {
    console.log(text);           /* ^this isn't an async function */
    await sleep(5);
    });
}

可以通过将异步函数作为回调传递来消除该错误,但是不建议将promise和回调流混合使用,这会导致问题,尤其是在处理错误时。这样可以防止您链接诺言并从run()外部的内部等待中捕获错误。

一种更好的方法是将fs.readFile()包装在一个诺言中,然后等待。

async function run() {
  await sleep(1);
  const text = await new Promise((resolve, reject) => {
    fs.readFile('list.txt', 'utf8', function (err, text) {
      if (err) reject(err) else resolve(text);
    });
  });
  console.log(text);
  await sleep(5);
}

这将使您可以使用以下更强大的方式捕获任何错误:

run()
.then(() => /*...*/)
.catch(err => /* handle error */

并避免未处理的拒绝。

答案 1 :(得分:4)

  

上面是测试的简化示例。在我的实际用法中,我需要将await睡眠置于深度嵌套在更多异步函数中的回调中。

在有机会遵守承诺的情况下,不应使用async..await来增强基于回调的API或一般而言的承诺(如果多次调用回调可能无法实现)。这会导致不良的控制流程和错误处理。

一旦async中有run个回调函数,就不可能将嵌套的promise与run().then(...)链接起来。嵌套承诺中的错误也可能无法处理,并导致UnhandledPromiseRejectionWarning

正确的方法是从回调转移到Promise,并使用Promise控制流。通常,这可以通过promise构造函数来实现:

async function run() {
  await sleep(1);
  const text = await new Promise((resolve, reject) => {
    fs.readFile('list.txt', 'utf8', function (err, text) {
      if (err) reject(err) else resolve(text);
    });
  });
  console.log(text);
  await sleep(5);
}

numerous ways可以从基于Node回调的API获得承诺,例如fs从节点10开始提供Promise API:

async function run() {
  await sleep(1);
  const text = await fs.promises.readFile('list.txt', 'utf8');
  console.log(text);
  await sleep(5);
}

答案 2 :(得分:0)

在功能启动之前,您必须使用 aysnc 键。 等待关键字 无法使用正常功能。

async function run() {
  await sleep(1);
  fs.readFile('list.txt', 'utf8', async function (err, text) {
    console.log(text);
    await sleep(5);
   });
}

run();

答案 3 :(得分:0)

如果函数包含“ await”,则必须必须在函数声明中添加“ async”前缀。

注意:通过将函数设为“异步”函数,将始终返回承诺。因此,如果您返回一个字符串,则该字符串将自动包装在Promise对象中。

因此,您可以手动返回Promise(为清晰起见)。一个简单的解决承诺就足够了:

async function foo(){
    await bar();
    return Promise.resolve('optional'); // optionally resolve with a value
}

关键字“异步”始终位于关键字“功能”之前:

var foo = async function(){
    await bar();
    return Promise.resolve('optional'); // optionally resolve with a value
}

...以及箭头功能很好:

var foo = sally( async () => {
    await bar();
    return Promise.resolve('optional'); // optionally resolve with a value
})

要获取返回值:

foo().then(val => console.log(val) ); // prints "optional" to console