翻自: How to use async and await in a forEach JS loop?

https://learn.coderslang.com/0144-how-to-use-async-and-await-in-a-foreach-js-loop/

事实上我们无法在 forEach 循环内使用 async/await 起到异步作用,让我们看看如何解决修复它。

async/await 在forEach 中为啥不起作用?

当你在forEach 循环内调用异步函数,下一个循环并不会等到上个循环结果后再被调用

想象一下,你有一个 getUsers 方法返回用户列表 User , user只有用户列表,但不包含具体的detail信息,所以你使用forEach 试图去获取用户详情

const users = await getUsers();

users.forEach(user => {
const details = user.getDetails();
console.log(details);
})

打印结果却是 3 个pending状态的 promise

你很自然的想到getDetails是个异步函数,需要给它加上await 关键字

const users = await getUsers();

users.forEach(user => {
const details = await user.getDetails();
console.log(details);
})

运行后发现报了另一个语法错误

SyntaxError: await is only valid in async function

你意识到给如果 forEach 传递的函数有是异步 则需要用 async 标记为异步函数

再次修复它

const users = await getUsers();

users.forEach(async (user) => {
const details = await user.getDetails();
console.log(details);
})

很好,你盯着半天发现并没有按users数组的顺序输出结果

解决方案:

你需要使用for 代替 forEach 循环重写这部分代码

const users = await getUsers();

for (let i = 0; i < users.length; i++) {
const details = await user.getDetails();
console.log(details);
}

也可以使用 for .... of

const users = await getUsers();

for (const user of users) {
const details = await user.getDetails();
console.log(details);
}

如果你实在不喜欢简单的代码,那么可以用个小技巧 使用 Array 的 map 方法

const users = await getUsers();

const userDetailsPromises = users.map(user => user.getDetails());
const userDetails = await Promise.all(userDetailsPromises); console.log(userDetails);

让我们一步步分析

1、第一行代码没有改变就是获取 users 数组

2、使用map循环调用 getDetails 返回新的 userDetailsPromises 数组,数组元素都为Promise类型

3、使用 await Promise.all 等待所有 Promise 处理完毕

4、最后打印出结果数组

代码也可以组合简化为

const userDetails = await Promise.all(users.map(user => user.getDetails()));

如何在forEach内使用异步调用 async/await的更多相关文章

  1. SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数

    SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...

  2. springboot:异步调用@Async

    在后端开发中经常遇到一些耗时或者第三方系统调用的情况,我们知道Java程序一般的执行流程是顺序执行(不考虑多线程并发的情况),但是顺序执行的效率肯定是无法达到我们的预期的,这时就期望可以并行执行,常规 ...

  3. MVC+Spring.NET+NHibernate .NET SSH框架整合 C# 委托异步 和 async /await 两种实现的异步 如何消除点击按钮时周围出现的白线? Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法

    MVC+Spring.NET+NHibernate .NET SSH框架整合   在JAVA中,SSH框架可谓是无人不晓,就和.NET中的MVC框架一样普及.作为一个初学者,可以感受到.NET出了MV ...

  4. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  5. .net 异步函数 Async await

    .net  异步函数  Async await 一旦为函数添加async关键字 该函数就是一个异步函数. 异步方法必须返回 void 或 Task<> 类型. public static ...

  6. 抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext

    长话短说,本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext 引言 C#异步编程语法糖async/await,使开发者很容易就能编写异步代码. ...

  7. 异步编程Async/await关键字

    异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ...

  8. javascript异步编程 Async/await

    Async/await Async/await 在学习他之前应当补充一定的 promise 知识 它是一种与 promise 相配合的特殊语法,目前被认为是异步编程的终级解决方案 值得我们每一个人学习 ...

  9. springboot 异步调用Async使用方法

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  10. springboot之异步调用@Async

    原文:http://www.cnblogs.com/xuwenjin/p/8858050.html 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交 ...

随机推荐

  1. 创建framework静态库和.a静态库

    在APP项目中使用的静态库有两种,一是.a静态库,另一种是framework静态库.下面分布介绍这2中静态库的创建过程,以及通过脚本工具做自动化打包的2种方式.   Framework静态库生成 如果 ...

  2. 在Visual Studio中部署GDAL库的C++版本(包括SQLite、PROJ等依赖)

      本文介绍在Visual Studio软件中配置.编译C++环境下GDAL库.SQLite环境与PROJ库的详细方法.   GDAL库是一个非常方便的地理数据处理库,但其在C++环境下的配置与编译流 ...

  3. linux 后台运行进程:& , nohup

    目录 后台执行 & nohup 查看后台运行的命令 jobs ps 关闭当前后台运行的程序 kill 前后台进程的切换与控制 ctrl + z 命令 fg 命令 bg 命令 思考 问题1-为什 ...

  4. [JVM]关于swap的理解

    关于swap的理解 概念 swap就是内存交换的意思. 计算机内存分为物理内存和虚拟内存.物理内存就是计算机实际内存的大小:虚拟内存是磁盘空间里开辟出一部分,是虚拟出来的内存空间,所以也叫磁盘缓存. ...

  5. 了解一下基本的http代理配置

    我们首先用一个简单例子了解一下基本的http代理配置 worker_processes 1; #nginx worker 数量 error_log logs/error.log; #指定错误日志文件路 ...

  6. 【Unity3D】使用GL绘制线段

    1 前言 ​ 线段渲染器LineRenderer.拖尾TrailRenderer.绘制物体表面三角形网格从不同角度介绍了绘制线段的方法,本文再介绍一种新的绘制线段的方法:使用 GL 绘制线段. ​ G ...

  7. 超详细的 springboot & mybatis 程序入门

    ps:网上有很多类似的入门案例,我也是看了被人的之后自己写的一个 估计有哥们懒 我把数据表格拿上来,数据自己填吧 CREATE TABLE `tb_user` ( `id` int(10) DEFAU ...

  8. 4.1k Star!全面的C#/.NET/.NET Core学习、工作、面试指南

    C#/.NET/.NET Core 学习.工作.面试指南 让现在的自己不再迷茫 . GitHub 开源地址:https://github.com/YSGStudyHards/DotNetGuide D ...

  9. golang 打隧道和端口转发

    `package main import ( "golang.org/x/crypto/ssh" "io" "log" "net& ...

  10. Android 全面屏体验

    一.概述 Android 应用中经常会有一些要求全屏显隐状态栏导航栏的需求.通过全屏沉浸式的处理可以让应用达到更好的显示效果.在 Android 4.1 之前,只能隐藏状态栏, 在 Android4. ...