简体   繁体   English

如何在回调中使用等待?

[英]How to use await in a callback?

My code is: 我的代码是:

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

run();

await sleep(1) is fine, but await sleep(5) results in: await sleep(1)很好,但是await sleep(5)导致:

SyntaxError: async is only valid in async function SyntaxError:async仅在异步函数中有效

Is fs.readFile the problem? fs.readFile是问题吗? How do I use await in such a situation? 在这种情况下如何使用await

The above is a reduced example to test. 以上是一个简化的测试例子。 In my actual usage, I need to put the await sleep in a callback deeply nested inside a few more asynchronous functions. 在我的实际使用中,我需要将await sleep置于一个深度嵌套在一些更多异步函数中的回调中。

I'm not sure what sleep is doing, but the problem in your question is happening because the callback to fs.readfile is not an async function and the that is where await sleep(5) is. 我不确定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);
    });
}

You could make that error go away by passing an async function as a callback, however mixing promise and callback flows is not recommended and leads to problems, especially when handling errors. 可以通过将异步函数作为回调传递来消除该错误,但不建议混合使用promise和回调流并导致问题,尤其是在处理错误时。 It prevents you from chaining the promise and catching errors from the inner await outside of run() . 它阻止你链接承诺并从run()之外的内部等待中捕获错误。

A better approach is to wrap fs.readFile() in a promise and await that. 更好的方法是将fs.readFile()包装在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);
}

This will allow you to catch any errors in much more robust way with: 这将允许您以更加健壮的方式捕获任何错误:

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

and avoid unhandled rejections. 并避免未经处理的拒绝。

The above is a reduced example to test. 以上是一个简化的测试例子。 In my actual usage, I need to put the await sleep in a callback deeply nested inside a few more asynchronous functions. 在我的实际使用中,我需要将await sleep置于一个深度嵌套在一些更多异步函数中的回调中。

Callback based APIs shouldn't be augmented with async..await or promises in general when there is a chance to stick to promises (may not be possible if a callback is called more than once). 当有机会坚持承诺时,不应使用async..await或promises来增加基于回调的API(如果多次调用回调,则可能无法实现)。 This results in poor control flow and error handling. 这导致较差的控制流和错误处理。

Once there is async callback function inside run , it's impossible to chain nested promise with run().then(...) . 一旦在runasync回调函数,就不可能用run().then(...)链接嵌套的promise。 Errors from nested promises may remain unhandled as well and result in UnhandledPromiseRejectionWarning . 嵌套承诺的错误也可能仍未处理,导致UnhandledPromiseRejectionWarning

The proper way is to move from callbacks to promises and use promise control flow. 正确的方法是从回调转移到承诺并使用承诺控制流程。 Generally this can be achieved with promise constructor: 通常,这可以使用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);
}

There are numerous ways to get promises from Node callback based APIs, eg fs provides promise API since Node 10: 许多方法可以从基于节点回调的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);
}

You have to use aysnc key before function start. 在函数启动之前必须使用aysnc键。 await keyword will not work with normal function. await关键字不能用于普通函数。

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

run();

If your function includes an "await", you must prefix your function declaration with "async". 如果您的函数包含“await”,则必须在函数声明前加上“async”。

NOTE: By making your function an "async" function a promise is always returned. 注意:通过使您的函数成为“异步”函数, 始终返回承诺。 So if you return a string, that string will get automatically wrapped in a Promise object. 因此,如果返回一个字符串,该字符串将自动包装在Promise对象中。

You can therefore return a Promise manually (for clarity). 因此,您可以手动返回Promise(为清楚起见)。 A simple resolved promise is sufficient: 一个简单的解决承诺就足够了:

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

The keyword "async" always goes before the keyword "function": 关键字“async”始终位于关键字“function”之前:

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

... and well for arrow functions: ......以及箭头功能:

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

To retrieve the return value: 要检索返回值:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM