我有以下几点:

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不会按顺序解决,但是我不希望自己的诺言在我调用resolve()之前就可以解决,所以即使没有顺序,我仍然希望交替记录。

为什么不是这样?

最佳答案

通过避免在新的手动创建的Promise中包装Promise的promise anti-pattern,可以使代码的编写更加简洁。取而代之的是,您只需将外部承诺发送到数组中,并通过从.then()处理程序内部将其返回,将内部承诺链接到外部承诺。可以像这样简单地完成所有操作:

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/

10-11 20:01