那么 block 不会在链式承诺中被调用
then block isn't get called in chained promises
我正在尝试在 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)
和 runPromise(3)
从未被调用?
你的问题是,在 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,它首先导致了这个错误。不要在外部 new Promise
执行器中调用 then
、new Promise
或 runPromise()
!而是使用
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) })
你这里或多或少有无穷无尽的递归。一旦你第一次设置了 promise =
,if(promise)
总是会进入,它总是会附加另一个 .then
回调,当被调用时,只是一次又一次地执行相同的函数。它也永远不会调用 res()
.
我通常会在这里分开关注:让一个函数构建承诺链并让它接受一个任务函数,该函数使用提供的值进行调用:
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);
我正在尝试在 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)
和 runPromise(3)
从未被调用?
你的问题是,在 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,它首先导致了这个错误。不要在外部 new Promise
执行器中调用 then
、new Promise
或 runPromise()
!而是使用
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) })
你这里或多或少有无穷无尽的递归。一旦你第一次设置了 promise =
,if(promise)
总是会进入,它总是会附加另一个 .then
回调,当被调用时,只是一次又一次地执行相同的函数。它也永远不会调用 res()
.
我通常会在这里分开关注:让一个函数构建承诺链并让它接受一个任务函数,该函数使用提供的值进行调用:
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);