参考:https://blog.youkuaiyun.com/qq_45265059/article/details/119892746
JS循环遍历中使用异步
对于同步顺序执行异步操作,并且每次异步操作都需要随着循环顺序执行
1、对于forEach
来说(慎用)
forEach
方法是同步的,也就是forEach
的回调函数都是同步调用的,在forEach
的回调里进行异步操作,每次遍历进行的这些异步操作会并行执行。它的每个迭代都会在前一个迭代完成之后立即执行。因此,在 forEach 中使用异步操作是不可能的,因为它将导致执行流阻塞,而且无法保证异步操作的完成顺序。
//定义一个异步函数
const foo1 = (i:any)=>{
return new Promise((resolve, reject) => {
setTimeout(() =>{
console.log(i);
resolve(i)
},1000)
})
}
const arr = [1,2,3,4,5]
const b = () =>{
arr.forEach(async e => {
console.log(e);
await foo1(e)
});
}
b(); // 1 2 3 4 5 1 2 3 4 5
2、对于for
循环来说(不推荐)
for
方法是异步的,也就是每次循环都能顺序执行异步操作
缺点:fo每次循环的作用域是用一个,可能会导致异步操作未结束就进入到下一个迭代中
//定义一个异步函数
const foo1 = (i:any)=>{
return new Promise((resolve, reject) => {
setTimeout(() =>{
console.log(i);
resolve(i)
},1000)
})
}
const arr = [1,2,3,4,5]
async function a() {
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
await foo1(arr[i])
}
}
a() // 输出:1 1 2 2 3 3 4 4 5 5
3、对于for of 循环(推荐)
其是ES6引入的一种新的循环接口,用于遍历可迭代对象,例如数组、Map和Set等。在使用异步操作时,for…of循环是最推荐的一种方式,因为它每次迭代都会创建一个新的作用域,可以保证异步操作的独立性和安全性。
它可以等异步执行结束后才进入下一个迭代
javascriptCopy codeasync function processData(data) {
for (const item of data) {
await doAsyncOperation(item);
}
}
async function doAsyncOperation(item) {
return new Promise((resolve, reject) => {
// 异步操作代码
});
}
在这个例子中,processData
函数使用 for...of
循环来遍历数据,并在每个迭代中等待异步操作完成。doAsyncOperation
函数返回一个 Promise
,以便 processData
函数可以等待它完成。这样,异步操作的执行顺序就得到了保证。
4、同时可以用Promise.all来
javascriptCopy codeasync function processData(data) {
const promises = data.map(doAsyncOperation);
await Promise.all(promises);
}
async function doAsyncOperation(item) {
return new Promise((resolve, reject) => {
// 异步操作代码
});
}
在这个例子中,processData
函数使用 map
方法来创建一个包含所有异步操作 Promise
的数组,并在数组上调用 Promise.all
方法。Promise.all
方法将等待所有异步操作完成,然后将它们的结果作为数组返回。这样,所有异步操作都将以并行方式执行。
总结:所以对于循环中调用异步操作的需求,慎用forEach(同步),不推荐for循环(每次迭代身处同一作用域),推荐使用for of以及promise.all二种方式