先說需求,根據數組中的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會遍歷所操作對象的所有可枚舉屬性,包括原型上的屬性和方法。
