async await结合forEach使用注意
场景:对一个对象或者数组遍历,其中一个值满足条件时请求接口,得到数据后进行后续代码操作
1.forEach回调函数直接结合async await使用,并不能将循环中的异步请求转为同步,得不到正常结果
Object.keys(propsAccountInfo).forEach(async (v) => { if (v === "bankId" && propsAccountInfo[v]) { await this.getBankBranchList(propsAccountInfo[v]); this.accountForm[v] = propsAccountInfo[v]; } });
2.改用for循环,能正常得到结果
for (let i = 0; i < Object.keys(propsAccountInfo).length; i++) { if ( Object.keys(propsAccountInfo)[i] === "bankId" && propsAccountInfo[Object.keys(propsAccountInfo)[i]] ) { await this.getBankBranchList( propsAccountInfo[Object.keys(propsAccountInfo)[i]] ); }
} // 上面代码异步请求接口以后再带入数据 Object.keys(propsAccountInfo).forEach((v) => { this.accountForm[v] = propsAccountInfo[v];
});
原因分析:
for:
const report = async () => { for (let i = 0, len = arr.length; i < len; i++) { await asyncFn(arr[i]); } };
forEach
const report = async () => { arr.forEach(async (item) => { await asyncFn(item); }); }; //相当于: const report = async () => { const asyncFnWrap = async (item) => { await asyncFn(item); }; for (let i = 0, len = arr.length; i < len; i++) { asyncFnWrap(arr[i], i); } };
第一个for循环的 asyncFn 要await返回后才继续执行,所以是顺序执行,而第二个的 asyncFnWrap 不会阻塞循环。
实际上还是forEach内部实现不支持await的问题:
Array.prototype.forEach = function (callback) { // this represents our array for (let index = 0; index < this.length; index++) { // We call the callback for each entry callback(this[index], index, this) } }
扩展一下
Array.prototype.forEachAsync = async function (fn) { for (let t of this) { await fn(t) } } Array.prototype.forEachAsyncParallel = async function (fn) { await Promise.all(this.map(fn)); }