首页 > 其他 > 详细

关于在forEach中使用await的问题

时间:2021-04-06 21:03:19      阅读:43      评论:0      收藏:0      [点我收藏+]

先说需求,根据数组中的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)
注意:

  1. 在es6中Object是被认为不可迭代的对象,不能用for···of来循环。
  2. for ···in会遍历所操作对象的所有可枚举属性,包括原型上的属性和方法。

关于在forEach中使用await的问题

原文:https://www.cnblogs.com/1258478q/p/14623106.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!