为了账号安全,请及时绑定邮箱和手机立即绑定

异步/ await如何拖慢你的Node.js应用

AsyncAwait 如何拖慢你的 Node.js 应用

How AsyncAwait Can Slow Down Your Node.js App

在 Node.js 世界里,async/await 已经成为了处理异步操作的标准。它干净、易读,感觉像同步一样。虽然听起来很棒,错误使用 async/await 可能会导致性能瓶颈,从而使应用变慢

尽管使用了 async/await,你的应用程序仍然感觉卡顿,这篇文章就是为你写的。

为什麼使用 Async/Await 感觉好慢

底层实现中,async/await 并没有做什么魔法 — 它只是将你的异步操作包裹成一个 Promise。如果使用不当,async/await 可能会引入 不必要的阻塞操作顺序处理 ,这会削弱 Node.js 的非阻塞和异步特性带来的优势。

这里有一些常见的场景,可能会拖慢你的应用程序,当使用异步/await时。

1. 顺序执行,而不是并行执行

异步/等待会一次只执行一个函数,除非你明确地将它们并行执行,使表达更贴合编程背景。举个例子:

    async function fetchUserData() {  
      const user = await getUser(); // 第一个获取请求  
      const orders = await getOrders(user.id); // 第二个获取请求  
      const profile = await getUserProfile(user.id); // 第三个获取请求  

      return { user, orders, profile: 个人资料 };  
    }

在这里,getUsergetOrdersgetUserProfile 的调用是按顺序执行的。每个调用都会等待前一个结束,从而增加了整体执行时间。

修复:使用Promise.all并行执行异步函数

为了不按顺序执行,我们可以把这些承诺并行处理:

    async function 获取用户数据() {  
      const [用户, 订单, 资料] = await Promise.all([  
        获取用户(),  
        获取订单(用户ID),  
        获取用户资料(用户ID),  
      ]);  

      return { 用户, 订单, 资料 };  
    }

使用 Promise.all,这三个请求会同时执行,大大缩短了执行时间。

2. N+1 查询问题

在循环中获取数据时,这种情况很常见。

    async function fetchOrderDetails(orders) {  
      const details = [];  

      for (const order of orders) {  
        const detail = await getOrderDetail(order.id); // 等待每个  
        details.push(detail);  
      }  

      return details;  
    }

每个 getOrderDetail 调用都等待前一个完成。如果你需要处理数百个订单,这种方法可能会非常慢,速度会让人感到痛苦。

使用**Promise.all**在循环中处理多个异步操作

而不是一个接一个地等待,同时发起所有请求:

    async function 获取订单详情(订单) {  
      const 详情 = 等待Promise.all(  
        订单.map(订单 => 获取订单详情(订单.id))  
      );  

      返回 详情;  
    }

这会大大提高性能,因为会并发运行这些承诺。

3. 拦截长尾操作

如果你将长时间运行的异步操作任务与关键代码混合,异步/等待的阻塞特性可能会延迟重要任务的执行。

    async function processRequest(req) {  
      const user = await getUser(req.userId); // 必须的  
      const analytics = await updateAnalytics(req); // 虽然不关键,但会阻塞用户获取  

      return { user, status: '已处理' };  
    }

虽然updateAnalytics是非关键性的操作,但还是拖慢了整体响应速度。

处理:把不太重要的任务单独处理一下

把不太重要的操作从主要流程里挪出去:

    async function processRequest(req) {  
      const user = await getUser(req.userId);  

      // 更新分析数据(无需等待结果)  
      updateAnalytics(req).catch(err => console.error('错误信息:', err));  

      return { user, status: '已处理' };  
    }

现在,updateAnalytics 在后台运行,不会影响到响应速度。

避开 Async/Await 坑的最佳方法
  • 批量处理承诺们
    使用 Promise.all 来分组可以并行运行的承诺们。
  • 限制并发数
    如果需要处理大量并行请求,可以使用 [p-limit](https://www.npmjs.com/package/p-limit) 这样的库来控制并发。
    const pLimit = require('p-limit');  
    const limit = pLimit(5); // 限制并发请求最多5个  

    const results = await Promise.all(  
      tasks.map(task => limit(() => asyncTask(task))) // 对每个任务执行异步任务,限制并发数
    );
  • 避免将已经同步的代码转换为异步/等待。
    保持异步工作流程独立且高效。
  • 按需调用昂贵的API。
    使用条件逻辑来决定何时调用它们。
    const profile = condition ? await fetchProfile(user.id) : null;

// 如果 condition 为真,则获取用户档案,否则 profile 为 null。

  • 使用工具进行调试
    工具如Clinic.js和Node.js自带的性能分析工具可以帮助识别异步问题。
最后的感想

异步/await是一种提升可读性和可维护性的绝佳工具,但也容易被误用。

记得,Node.js 擅长处理非阻塞的并发。明智地使用 async/await 函数,并在适当情况下利用并行处理(例如使用 Promise.all)。

你可能也会喜欢:

1)怎样才能让网站速度更快?

2)使用Artillery(负载测试工具)进行压力测试:为Node.js应用准备应对高峰流量期

3)软件开发面试中常见的十个问题及如何应对

4)[ 高级JavaScript Promise面试问题]( https://blog.arunangshudas.com/can-you-answer-this-senior-level-javascript-promise-interview-question/)

5)数据库索引是什么,为什么它很重要? ,了解数据库索引及其重要性。

6)AI能否改变交易格局?

7)部署管道的目的何在?

8)基于令牌的身份验证方法:在 JWT 和 Paseto 之间做选择以适用于现代应用

9)针对高流量 API 的 Node.js 中的 API 滥用预防和速率限制策略

更多相关博客请点击这里这里

在评论中分享一下你的经历,并让我们一起讨论如何解决这些!

关注我领英

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消