关于在forEach中使用await的问题
先说需求,根据数组中的ID值,对每个ID发送请求,获取数据进行操作。
首先肯定考虑用forEach 或者 map对数组进行遍历,然后根据值进行操作,但是请求是个异步操作,forEach又是一个同步操作,等同于同时发出多个异步请求,并不能确定具体返回的数据是哪个请求。(我这里的返回数据中有ID值,可以根据ID查找,这不就是太low了嘛,每次拿到返回来的数据,还得遍历一遍原数组才行)
那么我们如何才能做到即遍历数组又发送请求,同时根据返回值进行操作呐。
解释几点:(不想看的人直接跳结果)
async函数:返回一个promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体后面的语句。
await会获取promise的成功回调resolve()返回值,并且只能使用在async函数中(这表面这个函数中有异步操作)同时await将异步变成同步,增加了代码逻辑可读性。注意一点,既然是异步promise就有可能会有rejected的结果,所以一般使用try···catch···或者.catch 来处理请求出错
结果:
当需要同时发起多个异步,可以使用promise.all
// const aa = this.testNumArray.map((item) => {
// return this.getFetch(item);
// });
// const bb = Promise.all(aa);
// bb.then((val) => {
// console.log(val, 'bb-result');
// });
这里的getFetch就是发送的异步请求;
如果后一步的异步请求需要依赖于前一步的数据,即当一个异步请求完结后拿到数据才可以继续发送下一个请求,可以将for of和async/await结合使用
foo = async (array: any) => {
for (let i of array) {
const item = await this.getFetch(i);
console.log(item);
}
};
注意await这里等到的值,一定是一个promise对象(虽然他也可以处理非promise对象,同样可以作为resolve()的值进行输出)
这里解释一下,为何forEach是没有作用的,forEach的第一个参数是一个函数,他的源码中并没有对可遍历对象的异步进行处理,所以他是一个即时操作的回调函数,并不能达到我们异步的需求。
参考网址https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#polyfill
源码:
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
// 1. Let O be the result of calling toObject() passing the
// |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get() internal
// method of O with the argument "length".
// 3. Let len be toUint32(lenValue).
var len = O.length >>> 0;
// 4. If isCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let
// T be undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Let k be 0
k = 0;
// 7. Repeat, while k < len
while (k < len) {
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty
// internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Call the Call internal method of callback with T as
// the this value and argument list containing kValue, k, and O.
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined
};
}
这里看不懂没有关系,记住一点,红色的代码就是直接执行回调函数。
同时,人家官方都说了:如果使用 promise 或 async 函数作为 forEach() 等类似方法的 callback 参数,最好对造成的执行顺序影响多加考虑,否则容易出现错误
let ratings = [5, 4, 5];
let sum = 0;
let sumFunction = async function (a, b) {
return a + b;
}
ratings.forEach(async function(rating) {
sum = await sumFunction(sum, rating);
})
console.log(sum);
// Expected output: 14
// Actual output: 0
那么问题来了,既然forEach不行,那么for ··· of 为何可以呐?难道for ··· of比较牛逼嘛?
那话如果这么说,for ··· of真滴比较牛逼,因为for循环内置的是一个迭代器,通过Symbol.iterator对可迭代对象的循环。
这里就有一个面试常问到的地方,就是for···of和for···in有什么区别?
当然是遍历的值不同了(of:键值对,in:key值),还有原理实现上的不同,for···of只能对可迭代对象进行遍历循环。for···of可以视为一个迭代器,那么他也有迭代器能终止迭代的属性(break throw continue return)
注意:
- 在es6中Object是被认为不可迭代的对象,不能用for···of来循环。
- for ···in会遍历所操作对象的所有可枚举属性,包括原型上的属性和方法。
关于在forEach中使用await的问题的更多相关文章
- 聊一聊C# 8.0中的await foreach
AsyncStreamsInCShaper8.0 很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样. 简单说,其实就是C# 8.0中支持aw ...
- C#8.0中的 await foreach
AsyncStreamsInCShaper 8.0 C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>> sync Streams这个功能已经 ...
- C#中async/await中的异常处理
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
- 关于C#中async/await中的异常处理(下)-(转载)
上一篇文章里我们讨论了某些async/await的用法中出现遗漏异常的情况,并且谈到该如何使用WhenAll辅助方法来避免这种情况.WhenAll辅助方法将会汇总一系列的任务对象,一旦其中某个出错,则 ...
- 小心C# 5.0 中的await and async模式造成的死锁
平时在使用C# 5.0中的await and async关键字的时候总是没注意,直到今天在调试一个ASP.NET项目时,发现在调用一个声明为async的方法后,程序老是莫名其妙的被卡住,就算声明为as ...
- C#实现在foreach中删除集合中的元素
List<string> str = new List<string>(); str.Add( "zs"); str.Add("ls") ...
- C# 6.0:在catch和finally中使用await
Asyn方法是一个现在很常用的方法,当使用async和await时,你或许曾有这样的经历,就是你想要在catch块或finally块中使用它们,比如当出现一个exception而你希望将日志记在文件或 ...
- php在foreach中使用引用赋值&可能遇到的问题(转)
楼主在写项目的时候,由于初涉PHP的赋值引用操作,觉得这个功能非常强大,用时一时爽,没有深入了解过其中的原理,导致了一些当时觉得不可思议的BUG,废话不都说,我举个例子详细的描述一下这个问题. 代码: ...
- 关于C#中async/await中的异常处理(上)-(转载)
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
随机推荐
- Python module all in one
Python module all in one Python Modules https://docs.python.org/3/tutorial/modules.html Fibonacc # F ...
- dart 匹配基本map
var map_start = RegExp(r'^\s*\{\s*'); var map_end = RegExp(r'^\}\s*(,)?\s*'); var hasComma = true; M ...
- webpack + ts 配置路径别名无死角方法总结
webpack + ts 配置路径别名总结 自我体验加总结:在配置脚手架时,定制别名很有必要,可以使得代码更优雅,可读性更强.但在使用ts的时候,即便项目能够运行,vscode 确时长会提示 can' ...
- Python算法_斐波那契数列(10)
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项.斐波那契数列的定义如下: F(0) = 0, F(1) = 1F(N) = F(N - 1) + F(N - 2), 其中 ...
- 蓝绿部署、金丝雀发布(灰度发布)、A/B测试
本文转载自蓝绿部署.金丝雀发布(灰度发布).A/B测试的准确定义 概述 蓝绿部署.A/B测试.金丝雀发布,以及灰度发布.流量切分等,经常被混为一谈,影响沟通效率. 根本原因是这些名词经常出现,人们耳熟 ...
- 创建一个springboot项目
进入https://start.spring.io/ 再点击GENERATE,下载解压即可 注意配置好阿里云的仓库镜像,免得依赖无法下载 不下载最新版springboot是因为我在测试中遇到了问题,貌 ...
- IHttpClientFactory 踩过的坑
public class BasicUsageModel : PageModel { private readonly IHttpClientFactory _clientFactory; publi ...
- 自己写的一个抢票加速的Python小程序源码分享-----纯属娱乐
最近这段时间频频看到微信群里发什么 抢票加速,智行.携程.飞猪.美团,对于我这能坐客车就不坐火车的人来说,无所谓靠谱不靠谱 突发奇想的整理了下整个抢票加速的逻辑,写了这个小程序,代码很low,拒绝批评 ...
- Java 12 新特性介绍,快来补一补
Java 12 早在 2019 年 3 月 19 日发布,它不是一个长久支持(LTS)版本.在这之前我们已经介绍过其他版本的新特性,如果需要可以点击下面的链接进行阅读. Java 11 新特性介绍 J ...
- C语言柔性数组和动态数组
[前言]经常看到C语言里的两个数组,总结一下. 一.柔性数组 参考:https://www.cnblogs.com/veis/p/7073076.html #include<stdio.h> ...