我正在尝试重试JS中的一些异步调用。当简化并重写为setTimeout
时,逻辑看起来像这样:
let error = true
let promise = null
const runPromise = (value) => new Promise((res) => {
if (!error) {
res()
return
}
if (promise) {
return promise.then(() => {
return runPromise(value)
})
}
promise = new Promise((res2) => {
setTimeout(() => {
promise = null
console.log(value)
error = false
res2()
}, 1000)
}).then(() => res())
})
runPromise(1).then(() => { console.log(1) })
runPromise(2).then(() => { console.log(2) })
runPromise(3).then(() => { console.log(3) })
为什么then
和runPromise(2)
的{{1}}块从未被调用?
答案 0 :(得分:2)
您的问题是,在if (promise)
情况下,runPromise
返回的承诺永远不会res()
被解决。从执行程序回调中return
执行任何操作。您可以这样做
const runPromise = (value) => new Promise((res) => {
if (!error) {
console.log("resolve immediately without error")
res()
} else if (promise) {
promise.then(() => {
console.log("resolve after waiting for previous promise")
res(runPromise(value))
})
} else {
promise = new Promise((res2) => {
setTimeout(() => {
promise = null
error = false
res2()
console.log("resolve after timeout")
res()
}, 1000)
})
}
})
但实际上您应该避免使用Promise
constructor antipattern,它首先会导致此错误。不要在该外部then
执行程序中调用new Promise
,runPromise()
或new Promise
!而是使用
let error = true
let promise = null
function runPromise(value) {
if (!error) {
console.log(value, "resolve immediately without error")
return Promise.resolve();
} else if (promise) {
console.log(value, "defer until promise")
// now this `return` works as expected
return promise.then(() => {
console.log(value, "trying again")
return runPromise(value)
})
} else {
console.log(value, "starting timeout")
promise = new Promise(res2 => {
setTimeout(res2, 1000)
}).then(() => {
promise = null
error = false
console.log(value, "waited for timeout")
});
return promise;
}
}
runPromise(1).then(() => { console.log(1) })
runPromise(2).then(() => { console.log(2) })
runPromise(3).then(() => { console.log(3) })
答案 1 :(得分:0)
您或多或少在这里有无限的递归。首次设置promise =
后,if(promise)
将始终进入,并将始终附加另一个.then
回调,该回调在被调用时将一次又一次地执行相同的功能。它也永远不会调用res()
。
在这里,我通常会单独提出一些问题:让一个函数建立promise链,并让它接受一个任务函数,并使用提供的值来调用它:
let queue = Promise.resolve(); // no need for null, let it always be a promise
function runTask(task, ...args) {
return queue = queue.then(() => task(...args));
}
然后编写代表任务的另一个函数,例如在您的情况下,它是一个等待刻度的函数:
function waitTask(n) { return new Promise(res => setTimeout(res, 1000, n)); }
runTask(waitTask, 1);
runTask(waitTask, 2);
let queue = Promise.resolve();
function runTask(task, ...args) {
return queue = queue.then(() => task(...args));
}
function waitTask(n) { return new Promise(res => setTimeout(res, 1000, n)); }
runTask(waitTask, 1).then(console.log);
runTask(waitTask, 2).then(console.log);