最近老踩坑,在forEach里面,使用async和await不起效果,然后百度后发现原因,所以记录一下。先举个栗子:
<script>
let arr = [1, 2, 3];
let newArr = [11, 22]
function RunFn() {
newArr.forEach(async it => {
let text = await proRun();
console.log(it);
console.log(text);
arr.forEach(async item => {
let name = await proTest();
console.log(item);
console.log(name);
});
})
console.log('end');
};
RunFn();
function proRun() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我是第一个promise')
}, 1500)
})
}
function proTest() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我回来了')
}, 1000)
})
}
</script>
以上代码块,理想的执行顺序是:
11
‘我是第一个promise’
22
‘我是第一个promise’
1
‘我回来了’
2
‘我回来了’
3
‘我回来了’
1
‘我回来了’
2
‘我回来了’
3
‘我回来了’
‘end’
但是实际的数据顺序是:
会发现end,先被执行了,百度后,大概就是这样说的:
1、首先这是因为foreach是没有return返回值的(foreach内部实现只是简单的回调)
2、而foreach里面的回调函数因为加了async的原因,所以默认会返回一个promise,但是因为foreach的实现并没有返回值,所以导致返回的这个promise对象没人去管了
总的原因大概就是一句话:forEach 只支持同步,不支持异步
解决方法:
- for 循环:
所以要保证end先执行,就要把forEach更换,我最开始采用的是for循环,代码如下:
async function RunFn() {
for(let i=0;i<newArr.length;i++){
let text = await proRun();//''我是第一个promise''
console.log(newArr[i]);
console.log(text);
for(let j=0;j<arr.length;j++){
let name = await proTest();
console.log(arr[j]);
console.log(name);//''我回来了''
}
}
console.log('end');
};
RunFn();
执行顺序如下:
可以看见,结果确实跟预期的一样,并且执行顺序是从上到下一次执行的;但是由于for循环,如果次数多了我是很抗拒的,于是乎还是采用有返回值的map进行:
2. map():
先来一个简单的栗子:
<script>
let arr = [1, 2, 3];
async function RunFn() {
let map1Promise = await arr.map(async it => {
let text = await proRun(); //''我是第一个promise''
console.log(it);
console.log(text);
});
console.log(map1Promise); // return=>>[Promise, Promise]
console.log('end');
};
RunFn();
function proRun() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我是第一个promise')
}, 1500)
})
}
</script>
执行顺序:
这里可以看出map返回的是一个包含promise对象的数组[promise, promise, promise],然而await只能处理一个promise对象,所以就可以采用Promise.all()的方法:
<script>
let arr = [1, 2, 3];
async function RunFn() {
await Promise.all(arr.map(async it => {
let text = await proRun(); //''我是第一个promise''
console.log(it);
console.log(text);
}))
console.log('end');
};
RunFn();
function proRun() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我是第一个promise')
}, 1500)
})
}
</script>
执行顺序为:
最后在去试试之前的多个循环:
<script>
let arr = [1, 2, 3];
let newArr = [11, 22]
async function RunFn() {
await Promise.all(newArr.map(async it => {
let text = await proRun(); //''我是第一个promise''
console.log(it);
console.log(text);
await Promise.all(arr.map(async item => {
let name = await proTest();
console.log(item);
console.log(name); //''我回来了''
}));
}))
console.log('end');
};
RunFn();
function proRun() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我是第一个promise')
}, 1500)
})
}
function proTest() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve('我回来了')
}, 1000)
})
}
</script>
执行顺序: