文章目录
前言
在js中某些场景需要用到数组循坏中使用异步的操作,在这种情况下我们可能会面临这些问题
如:
- 如何让所有的循环中的Promise异步操作结束后执行再执行某个操作
- 如何在循环中的Promise异步操作按顺序等待上一个完成后再执行下一个异步操作
这是我的一些实现思路,如下
如何让所有的循环中的Promise异步操作结束后执行某个操作
定义一个异步方法
function myFunc(num, s = 1000) {
return new Promise(resolve => {
setTimeout(() => {
resolve("我是数组的第"+ num + '项');
}, s);
});
}
标记计数法
定义一个初始为0的变量,每次循环异步结束后+1,直到变量和数组长度相同,就可以判断为当前异步操作全部完成
代码如下:
使用for(推荐)
let flag = 0 // 标记变量
let arr = [6, 2, 3, 4, 5] // 循环数据
// 使用for
for (let i = 0; i < arr.length; i++) {
myFunc(i, arr[i]).then(res => { // myFunc异步方法
flag++ // 每次返回结果后+1
console.log(res)
if (flag === arr.length) {
console.log('这里的块级作用域为所有异步循环完成后')
}
})
}
使用forEach
let flag = 0 // 标记变量
let arr = [1, 2, 3, 4, 5] // 循环数据
arr.forEach((item, idx) => {
myFunc(idx, item).then(res => { // myFunc异步方法
flag++ // 每次返回结果后+1
console.log('单个异步回调')
if (flag === arr.length) {
console.log('这里的块级作用域为所有异步循环完成后')
}
})
})
使用es9方法 for await of
let flag = 0 // 标记变量
let arr = [1, 2, 3, 4, 5] // 循环数据
const promise_all = arr.map(item => myFunc(item))
async function test() {
for await (const prop of promise_all) {
flag++ // 每次返回结果后+1
console.log('单个异步回调')
if (flag === arr.length) {
console.log('这里的块级作用域为所有异步循环完成后')
}
}
}
test()
Promise.all()
可以使用Promise.all()
将Promise实例,包装成一个新的 Promise 总实例
首先利用循环生成实例
在执行合并起来的promise异步实例
const Promise_All = Promise.all(arr.map(item => Files.findOne(item))) // Files.findOne异步方法
const res = await Promise_All // 执行总实例
console.log(res, '所有异步循环完成后')
如何在循环中的异步操作按顺序等待上一个完成后再执行下一个异步操作
这种需求通常用于第二个异步方法需要获取上一个异步方法返回的状态才能进行下一步,或者在使用分片上传时,将分片文件按顺序上传
假设模拟分片上传场景
let flag = 0 // 标记变量
let arr = [3, 2, 1, 3, 2] // 循环数据
// 使用for
for (let i = 0; i < arr.length; i++) {
myFunc(i, arr[i]).then(res => { // myFunc异步方法
flag++ // 每次返回结果后+1
console.log(`第${i}个分片文件上传完了`)
if (flag === arr.length) {
console.log('所有分片文件都上传完了')
}
})
}
可以看到由于是异步,谁先最快就返回谁,这肯定不符合我们的需求,导致产生莫名奇妙的bug
怎么实现执行等待呢,其实很简单,在上面异步循环原有例子中 增加 await
即可
let flag = 0 // 标记变量
let arr = [3, 2, 1, 3, 2] // 循环数据
// 使用for
async function test() {
for (let i = 0; i < arr.length; i++) {
await myFunc(i, arr[i]).then(res => { // myFunc异步方法
flag++ // 每次返回结果后+1
console.log(`第${i}个分片文件上传完了`)
if (flag === arr.length) {
console.log('所有分片文件都上传完了')
}
})
}
}
test()
这样就可以按顺序执行了,解决
注意:
实际开发中for、while、for in、for of、for await of使用await都是生效的;其中for await of是等待整个for循环作用域,异步返回后才执行当前作用域下的其他操作;而其他则是局部等待
有回调的遍历方法:forEach、map、filter、reduce、some、every、find等,使用await都是不生效的;