问题
在forEach使用 async 和 await时,期望结果和实际结果不一致
期望结果: 隔一秒打印1次 1, 2, 3, 4 总时长 4s
实际结果: 一秒之后 1, 2, 3, 4全被打印 总时长 1s
let array = [1, 2, 3, 4]
const fun1 = (val) => {
return new Promise((reslove, reject) => {
setTimeout(() => {
reslove('1')
console.log(val)
}, 1000)
})
}
array.forEach(async function (item) {
await fun1(item)
})
原因分析
参考资料
MDN描述:forEach() 期望的是一个同步函数,它不会等待 Promise 兑现。在使用 Promise(或异步函数)作为 forEach 回调时,请确保你意识到这一点可能带来的影响。
// 自己实现一个myForEach方法
Array.prototype.myForEach = function(callBack, thisArg) {
for(let i = 0; i < this.length; i++) {
callBack.call(thisArg, this[i], i, this)
}
}
从上面代码可以看出,myForEach内部执行callBack时,没有await关键字。
解决:
方案1.使用 for循环代替forEach
let array = [1, 2, 3, 4]
const fun1 = (val) => {
return new Promise((reslove, reject) => {
setTimeout(() => {
reslove('1')
console.log(val)
}, 1000)
})
}
const fun2 = async () => {
for (let i = 0; i < array.length; i++) {
await fun1(array[i])
}
}
fun2()
项目中例子记录
-
需求:让DOM元素逐个出现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.divStyle {
display: inline-block;
margin: 10px;
width: 100px;
height: 100px;
scale: 0;
transition: all .5s ease-in-out;
background: grey;
border: 5px;
}
</style>
</head>
<body>
<script>
function createDiv() {
const divEl = document.createElement('div')
divEl.classList.add('divStyle')
setTimeout(() => {
divEl.style.scale = 1
}, 50)
document.body.appendChild(divEl)
}
const addDivFun = async () => {
for (let i = 0; i < 10; i++) {
const fun = () => {
return new Promise((reslove) => {
setTimeout(() => {
createDiv()
reslove()
}, 1000)
})
}
await fun()
}
}
addDivFun()
</script>
</body>
</html>