開發中遇見個難題很苦惱,好在我解決了,只要能解決我就很開心😄😄😄
本篇文章從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肯不是同步關系,要想同步必須在一個函數。
至此已經結束了。當然還有其他解決方案 有時間接着整理