bluebird 如何知道继续执行此链中的下一个“then”?

How does bluebird know to proceed to the next `then` in this chain?

通过 promisified fs-extra,我知道我可以使用 then 访问文件。我 猜测 那里有某种机制,在它获得文件后它知道移动到 then 链中的下一个 link。但是,接下来 then 我只是放了一个简单的 for 循环。下一个只是向控制台打印一行。我希望返回某种 Promise 对象,以便它沿着链向下移动。沿着这条链向下推进需要什么?例如,如果我将 setTimeout 设置为一秒钟,那么链会继续并乱序打印。

var Promise = require('bluebird')
  , fs = Promise.promisifyAll(require('fs-extra'))

fs.readdirAsync(dir)
    .bind(this)
    .then((files) => {
        this.files = files;
    })
    .then(() => {
        var num = 10000
        this.files.forEach((file, index, array) => {
            for(i = 0; i < num; i++){
                console.log(num*i);
            }
        });
    })
    .then(() => {
        console.log('middle of it');
    })
    .then(() => {
        console.log('done with it');
    })
    .catch((err) => {
        console.log(err);
    });

每次调用 .then() return 都是一个新的承诺,它有自己的 .then() 处理程序。该承诺会自动链接到先前的承诺,因此当先前的承诺完全用它自己的 .then() 处理程序完成并且 .then() 处理程序没有 return 承诺时承诺它 returned 已解决,然后它可以触发链中的下一个承诺被解决,导致它为它的 .then() 处理程序重复循环。

关键是 p.then() return 是一个新的 promise,当 p.then() 完成时它本身就被解决了,因此它可以触发链中的下一步 p.then().then()等等。

请记住,.then() 处理程序可以执行以下四种操作之一:

  1. Return 无(与 returning undefined 相同)。
  2. Return一个值
  3. Return一个承诺
  4. 抛出异常

对于前两个(returning 值),这仅表示 .then() 处理程序已完成,现在可以触发链中的下一个处理程序。

当 return 承诺时,该承诺本身与 .then() 处理程序挂钩,因此可以对其进行监视。 If/when 它解决了,链继续。 If/when it rejects,链被拒绝。 returned 的 promise 可能已经被解决或拒绝,或者可能在未来被解决或拒绝,在行为上没有有意义的差异。如果 returned promise 从未被解决或拒绝,则 promise 链将停止并且不会继续,直到它被解决或拒绝(与任何承诺相同)。

如果 .then() 处理程序抛出异常,这会被 .then() 包装器捕获,并自动转换为拒绝承诺,并将异常作为拒绝原因。

For example, if I put in a setTimeout for a second, then chain continues and prints out of order.

您不能非常有效地单独使用 setTimeout() 来延迟承诺链。相反,您需要 return 来自 .then() 处理程序的承诺,该承诺在一段时间后得到解决。 Bluebird .delay(x) 可以为您做到这一点。

或者,如果不使用 Bluebird,您可以自己编写一个代码:

function delay(t) {
    return new Promise(function(resolve) {
        setTimeout(resolve, t);
    });
}

fn().then(function() {
    // delay promise chain by 1000ms
    return delay(1000);
}).then(function() {
    // promise chain continues here
});

或者,使用 Bluebird 承诺,它就像:

 fn().delay(1000).then(function() {
     delayed promise chain continues here
 });