foreach的异步(async,await)的问题及其处理方式
开发中遇见个难题很苦恼,好在我解决了,只要能解决我就很开心😄😄😄
本篇文章从forEach方法 到promise 到async await统统理解个遍,进入正题
先看下面代码会出现什么问题:
const arr = [1,2,3,4,5,6]; const result = []; const fn = (item) => { let time = Math.ceil(Math.random()*1000) return new Promise(resolve => { setTimeout(() => { resolve(item) }, time); }) } arr.forEach(async (item) => { const val = await fn(item); result.push(val); console.log(result); })
输出结果顺序,看随机数的脸色。 可能是[6, 5, 4, 1, 3, 2] 或者 [3, 5, 4, 6, 1, 2] 或者等等。。。。。。。
那么问题来了
问题1: 我想在这个forEach执行完之后怎么按arr的顺序得到结果
问题2: 怎么等所有异步执行完成拿到result,再执行以后的代码。
今天就伴随这俩问题我们开始整
const result1 = []; (async()=>{ for(let i = 0; i < arr.length; i++){ const val1 = await fn(arr[i]); result1.push(val1); } //在这里拿到执行结果result,再执行依赖result的代码 console.log(result1); })();
这个结果妥妥的解决了,得到的顺序是 [1, 2, 3, 4, 5, 6],知道为啥吗?你要知道那你可以走了 拜拜👋
接着来, 我们不是未来解决问题而解决问题。接下来就要搞清楚forEach为啥不行
看下forEach的实现源码:
// 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 }; }
看完你会发现:
forEach每次执行都会执行一个回调函数,是不是听不大明白,举个例子
async function fn2 (){ let val2 = await fn(1); console.log(val2) }; async function fn3 (){ let val3 = await fn(2); console.log(val3) }; fn2(); fn3();
forEach的回调函数就好比这样,这个很容易看懂fn2和fn3肯不是同步关系,要想同步必须在一个函数。
至此已经结束了。当然还有其他解决方案 有时间接着整理