JS:闭包循环中的setTimeout问题



我正在练习一些Promise和闭包。我有一个forEach循环,其中我返回一个Promise,超时3秒,在Promise解析后,它应该记录一条语句。

我认为我做得不对,因为我希望每3秒看到一个"111"的日志,然后是"222",但我看到了3秒的延迟,然后立即是3个"111""222"的日志。

let arr = [1,2,3];
arr.forEach((x,i) => {
(function() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})()
.then(() => {console.log("222")})
});

您只是忘记告诉javascript"等待";for循环每次迭代之间的超时。因此,javascript将运行for循环,在这样做的同时安排三次超时,然后这三次超时都会同时发生。

如果你像这样添加一个等待,那么它会像你预期的那样工作。

(async function() {
let arr = [1, 2, 3];
for (let x of arr) {
await (function() { // <-- await added
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})()
.then(() => {
console.log("222")
})
}
})()

我切换到的for,因为.forEach((不适用于异步函数。我还将整个代码封装在异步IIFE中,因为那里不允许使用顶级等待——根据您将代码放在哪里,您可能不必将其封装在异步IIS中。

编辑

刚刚意识到,在最初的问题中,您没有在任何地方使用async/await。我不知道你是否已经了解了它,但你不必知道它就能解决这个特定的问题。

这里有另一种不用async/await的方法。

let arr = [1, 2, 3];
let promise = Promise.resolve();
arr.forEach((x,i) => {
promise = promise
.then(function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("111")
resolve(true)
}, 3000);
})
})
.then(() => {
console.log("222")
})
});

这基本上是在循环中构建一个承诺链。如果你";展开";循环,它看起来像这样:

promise = Promise.resolve()
promise = promise
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })
.then(() => /* wait 3000 ms and log "111" */)
.then(() => { console.log("222") })

因为我们一直在引用上一个承诺,并一直坚持到最后,所以我们坚持的每一件新事情都会在最后一件事情完成后发生。

最新更新