promise-chaining是否保证只有在前一个promise完成后才会调用下一个promise的回调?

时间:2017-07-08 12:05:28

标签: javascript asynchronous promise

我遇到了article about promises in js,作者在其中显示了一段代码:

// I want to remove() all docs
db.allDocs({include_docs: true}).then(function (result) {
  result.rows.forEach(function (row) {
    db.remove(row.doc);  
  });
}).then(function () {
  // I naively believe all docs have been removed() now!
});

并说

  

此代码有什么问题?问题是第一个问题   函数实际上是返回undefined,意思是第二个   函数不等待所有的db.remove()被调用   文档。实际上,它不是在等待任何东西,而是可以在何时执行   已删除任意数量的文档!

所以,据我所知,如果第二个回调function() {}不接受任何参数,它实际上不会等待回调结束function(result)。我是否正确推断?因为当我运行以下代码时,它给出了相反的结果:

var array = [];
for ( let i = 0; i < 1000; i++ )
    array.push(i);

var promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 1000);
});

promise
.then(() => array.forEach(item => console.log(item)))
.then(() => console.log("invoked earlier"));

我等待“先前调用”出现在打印数字的中间。但无论物品的数量有多大都无关紧要。 “先前调用”总是出现在最后。有人可以解释我错过了什么吗?也许这篇文章已经过时了,从那以后发生了一些变化?

1 个答案:

答案 0 :(得分:4)

为了保证这一点,你实际上必须从先前的承诺中返回承诺。

无论您从承诺中返回,都会被传递到下一个承诺。

在您的情况下,您返回undefined

相反,如果您返回了一个承诺,那么承诺将被解决,第二个承诺将在发生之后运行,并且将传递承诺解决的任何值。

所以是的,承诺保证会一个接一个地运行,但是如果你选择在回调中做一些异步,并且不想通过返回将它链接回承诺,那么他们就可以了。我不愿意等待任何事情(因为他们不知道还有什么需要等待的。)

我假设db.remove返回承诺......

...所以,知道我们必须从回调中返回一个promise,为了让它实际等待异步事件发生,我会做这样的事情。

.then(result => Promise.all(result.rows.map(row => db.remove(row.doc))))
.then((listOfRemoves) => console.log(`removed`));

第二个函数运行时,第二个函数是1还是0参数是100%无关紧要的。

修改

的示例:

.then(() => setTimeout(() => console.log('2nd', 20000)))
.then(() => console.log('first'));

这是因为第一个不知道发生了setTimeout。它不是一个读者,只是运行代码并传递返回值(在本例中为undefined)。

如果返回值恰好是一个承诺,它将等到该承诺完成,从中获取值,然后传递

.then(() => new Promise(resolve => setTimeout(resolve, 20000)))
.then(() => console.log('I waited 20 seconds.'));

因为它会返回一个承诺,它会调用该承诺的then,并等待获取该值,然后传递。

您的测试失败的原因是因为您基本上是这样做的。

.then(() => console.log('first'))
.then(() => console.log('second'));

这些保证按此顺序触发。期。 所有其他的也按顺序开火。只是他们调度异步进程,就像在JS中使用异步I / O的所有其他回调/超时一样。