理解 Node JS 中的 async/await

Posted

技术标签:

【中文标题】理解 Node JS 中的 async/await【英文标题】:Understanding async/await on NodeJS 【发布时间】:2017-11-14 16:39:47 【问题描述】:

我认为我对它的理解可能会受到我使用 .NETasync/await 的经验的影响,所以我想要一些代码示例:

我正在尝试让快速控制器在返回响应之前等待 5 秒:

const getUsers = async (ms) => 
  var wait = ms => new Promise(resolve => setTimeout(resolve, ms));

  await wait(ms);
;


export const index = (req, res) => 
  async () => 
    await getUsers(5000);

    res.json([
      
        id: 1,
        name: 'John Doe',
      ,
       id: 2,
        name: 'Jane Doe',
      ,
    ]);
  ;
;

此代码不起作用,浏览器不断加载和加载,从不显示任何内容。

我基于this SO answer 构建的getUser 函数和控制器方法,基于我对它如何工作的(错误的)理解,所以我想要一些澄清和更正:

1.我什么时候应该使用await

据我了解,您应该在 async 函数调用之前使用 await。它是否正确?另外,为什么我可以在返回 promise 的非异步函数之前调用 await?

2。我应该什么时候使用async

据我了解,您将函数标记为async,以便可以使用await 关键字调用它。它是否正确?另外,[为什么]我必须将我的 await getUsers(5000) 调用包装在匿名异步函数中?

【问题讨论】:

不要将东西包装在异步匿名函数中,这在您的代码中也永远不会执行。而是使索引函数异步并删除函数包装并返回 res.json 【参考方案1】:

解几个疑惑——

    您可以将await 与任何返回承诺的函数一起使用。您等待的函数不一定是async。 当您想在函数中使用await 关键字时,您应该使用async 函数。如果您不打算在函数中使用 await 关键字,那么您不需要创建该函数 asyncasync 函数默认返回一个承诺。这就是您能够await async 函数的原因。

来自MDN -

当一个异步函数被调用时,它会返回一个 Promise。

就你的代码而言,它可以这样写 -

const getUsers = (ms) =>  // No need to make this async
    return new Promise(resolve => setTimeout(resolve, ms));
;

// this function is async as we need to use await inside it
export const index = async (req, res) => 
    await getUsers(5000);

    res.json([
      
        id: 1,
        name: 'John Doe',
      ,
       id: 2,
        name: 'Jane Doe',
      ,
    ]);
;

【讨论】:

这个解释很清楚。现在,剩下的就是将导出的异步函数 index(这是一个返回承诺的函数)与 express 路由器连接起来,其中一个接受承诺的 router.get 变体。这是正确的吗? 是的,在 Express 中你可以像这样使用它 - router.get('/users', index)【参考方案2】:

async await 只是 Promise 的语法糖。

当您希望代码在函数完成时运行时,您可以像使用 Promise 一样使用它们。

async function asyncOperation(callback) 
    const response = await asyncStep1();
    return await asyncStep2(response);

如果你使用 promises 的语法,那是正确的:

function asyncOperation() 
  return asyncStep1(...)
    .then(asyncStep2(...));

新的 async/await 语法允许您仍然使用 Promises,但它消除了为链接的 then() 方法提供回调的需要。

回调直接从异步函数返回,就像它是一个同步阻塞函数一样。

let value = await myPromisifiedFunction(); 

当你计划在你的函数中使用 await 时,你应该用 async 关键字标记你的函数(就像在 c# 中一样)

您不必将 getUsers 创建为匿名函数。

【讨论】:

【参考方案3】:

您可以在async 函数中await 任何承诺。 await后面的代码会在你等待的promise完成后执行。

这是经典 javascript 回调的绝佳替代方案。

我写了一篇关于它的博客 -> https://github.com/Gameye/js-async我希望这对你有帮助!

【讨论】:

【参考方案4】:

Javascript 中的异步函数

async 关键字将常规 JS 函数声明转换为异步函数声明:

function syncFunc // dostuff
async function asyncFunc // dostuff // the async keyword is placed before the function keyword

一个异步函数返回一个 Promise:

当 async 函数返回值时,Promise 将使用返回值进行解析。 当异步函数抛出异常或某个值时,Promise 将被抛出的值拒绝。

在异步函数中,您可以使用 await 关键字。 await 放置在 promise 之前会导致异步函数暂停,直到 promise 被解决(拒绝或履行)

。当 Promise 完成时 await 表达式的值就是完成的 Promise 的值。 当 promise 被拒绝时,await 表达式抛出被拒绝的值。

示例:

function makePromise(x)  
    return new Promise(resolve => 
      setTimeout(() => 
        resolve(x);
      , 1000);
    );
  
  
  async function asyncFunc() 
    var x = await makePromise(1); // the function is paused here until the promise is fulfilled
    console.log(x); // logs 1
    return x;
  
  
  const returnedProm = asyncFunc(); // the async func returns a promise


  returnedProm.then((x) => console.log(x));
  // This promise is fulfilled with the return value from the async func, so this logs 1

何时使用异步函数:

当您有多个相互依赖的异步操作(作为 Promise 实现)时,异步函数是一个有用的工具。例如,当您的第二个承诺需要您的第一个承诺将提供的数据时。您现在可以方便地使用await 关键字首先接收promise 1 中的数据,然后将此数据作为参数传递给promise 2。

换句话说,async 函数可以通过await 关键字使异步编程表现得像同步编程一样。因此,您的应用程序更容易理解。

【讨论】:

漂亮地说:换句话说,async 函数可以通过 await 关键字使异步编程表现得像同步编程。因此,您的应用程序更容易理解。

以上是关于理解 Node JS 中的 async/await的主要内容,如果未能解决你的问题,请参考以下文章

JS中的async/await的用法和理解

node.js异步控制流程 回调,事件,promise和async/await

Node.js 7 的 async await 终于来了,不过怎么觉得没啥用

理解 JavaScript 的 async/await

Node.js 最佳实践异常处理——在 Async/Await 之后

Node.js 使用 async/await 读取文件