我有以下内容:
for (let job of jobs) {
resets.push(
new Promise((resolve, reject) => {
let oldRef = job.ref
this._sequenceService.attachRef(job).then(() => {
this._dbService.saveDoc('job', job).then(jobRes => {
console.log('[%s / %s]: %s', oldRef, jobRes['jobs'][0].ref, this._moment.unix(job.created).format('DD/MM/YYYY HH:mm'))
resolve()
}).catch(error => {
reject(error)
})
}).catch(error => {
reject(error)
})
})
)
}
return Promise.all(resets).then(() => {
console.log('Done')
})
this._sequenceService.attachRef
有一个 console.log()
称呼。
运行时,我看到了来自 this._sequenceService.attachRef()
的所有控制台日志打电话,然后我在 saveDoc.then()
中看到所有日志称呼。我期待看到他们交替出现。我的理解是根据 this文章, promise 不会按顺序解决,但我不希望我的 promise 得到解决,直到我调用 resolve()
所以仍然期望交替日志,即使不是按顺序。
为什么不是这样?
最佳答案
通过避免 promise anti-pattern,您的代码可以写得更清晰在新的手动创建的 promise 中包装 promise 。相反,您只需将外部 promise 插入您的数组,并通过从 .then()
处理程序内部返回它们将内部 promise 链接到外部 promise。这一切都可以像这样简单地完成:
for (let job of jobs) {
let oldRef = job.ref;
resets.push(this._sequenceService.attachRef(job).then(() => {
// chain this promise to parent promise by returning it
// inside the .then() handler
return this._dbService.saveDoc('job', job).then(jobRes => {
console.log('[%s / %s]: %s', oldRef, jobRes['jobs'][0].ref, this._moment.unix(job.created).format('DD/MM/YYYY HH:mm'));
});
}));
}
return Promise.all(resets).then(() => {
console.log('Done')
}).catch(err => {
console.log(err);
});
拒绝将自动向上传播,因此您不需要在循环内使用任何 .catch()
处理程序。
至于排序,情况如下:
for
循环是同步的。它会立即运行完成。- 对
.attachRef()
的所有调用都是异步的。这意味着调用它们只是启动操作,然后它们返回,其余代码继续运行。这也称为非阻塞。 - 所有
.then()
处理程序都是异步的。他们最早可以在下一个滴答时运行。 - 因此这解释了为什么首先发生的事情是所有对
.attachRef()
的调用都执行,因为这就是循环所做的。它立即调用所有.attachRef()
方法。因为他们只是开始他们的操作然后立即返回,for
循环完成它的工作很快启动所有.attachRef()
操作。 - 然后,当每个
.attachRef()
完成时,它会触发相应的.saveDoc()
被调用。 .saveDoc()
调用完成之间的相对时间只是一场比赛,取决于他们何时开始(他们的.attachRef()
在他们之前来了多久花了) 以及他们自己的.saveDoc()
调用执行了多长时间。所有这些的相对时间可能无法完全预测,特别是如果幕后有一个可以同时处理多个请求的多线程数据库。
相对时间不可预测这一事实不足为奇。您有意并行运行多个两阶段异步操作,这意味着您不关心它们运行或完成的顺序。它们都在相互竞争。如果它们都花费完全相同的时间来执行而没有变化,那么它们可能会以相同的启动顺序完成,但执行时间的任何微小变化肯定会改变完成顺序。如果底层 DB 同时在所有不同的请求之间发生锁争用,那也会大大改变时间。
因此,此代码旨在并行执行操作并在所有操作完成时通知您。从某种意义上说,这意味着您不关心控制事情运行或完成的精确顺序,只有当它们全部完成时。
关于javascript - promise 没有以我期望的方式解决,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48315459/