循环通过任务瀑布 – 承诺蓝鸟

我正在寻找循环通过蓝鸟一些任务,只是使用超时作为实验机制。 [不希望使用asynchronous或任何其他库]

var Promise = require('bluebird'); var fileA = { 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five' }; function calculate(key) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(fileA[key]); }, 500); }); } Promise.map(Object.keys(fileA), function (key) { calculate(key).then(function (res) { console.log(res); }); }).then(function () { console.log('finish'); }); 

结果是

 finish, one, two, three, four, five, 

我需要循环只遍历每个超时完成,然后发射最后一个完成。

  1. 在传递给Promise.map的函数对象中,您需要返回一个Promise对象,以便所有的Promise将被parsing,并且parsing值的数组可以传递到下一个函数。 在你的情况下,因为你没有明确地返回任何东西, undefined将被返回,默认情况下,不是一个承诺。 因此,当Promise.map中的Promises.map被parsing为undefinedfinish的thenable函数被执行。 你可以这样确认

     ... }).then(function (result) { console.log(result); console.log('finish'); }); 

    会打印

     [ undefined, undefined, undefined, undefined, undefined ] finish one two three four five 

    所以,你的代码应该有这样的return语句

     Promise.map(Object.keys(fileA), function (key) { return calculate(key).then(function (res) { console.log(res); }); }).then(function () { console.log('finish'); }); 

    现在,您将看到代码将按顺序打印这些东西,因为我们返回Promise对象,并在所有Promiseparsingfinish后调用可执行的finish函数。 但是他们都没有顺序解决。 如果发生这种情况,在指定的时间过后,每个数字都会被打印出来。 这将我们带到第二部分。

  2. Promise.map被parsing, Promise.map将执行作为parameter passing的函数。 引用文档,

    尽可能快地调用给定项目的映射器函数,也就是说,当input数组中的项目索引的承诺得到满足时。

    因此,数组中的所有值都被转换为Promises,并使用相应的值进行parsing,并且将立即为每个值调用该函数。 所以,他们都在同一时间等待500毫秒,立即解决。 这不会顺序发生。

    既然你希望他们顺序执行,你需要使用Promise.each 。 引用文档,

    迭代发生连续。 ….如果迭代器函数返回一个promise或者一个thenable,那么在继续下一次迭代之前,等待promise的结果。

    由于承诺是连续创build的,并在继续之前等待解决,所以结果的顺序是有保证的。 所以你的代码应该成为

     Promise.each(Object.keys(fileA), function (key) { return calculate(key).then(function (res) { console.log(res); }); }).then(function () { console.log('finish'); }); 

    附加说明:

    如果按照 Benjamin Gruenbaum的build议, 顺序并不重要 ,那么可以使用Promise.map本身, concurrency限制就像这样

     Promise.map(Object.keys(fileA), function (key) { return calculate(key).then(function (res) { console.log(res); }); }, { concurrency: 1 }).then(function () { console.log('finish'); }); 

    concurrency选项基本上限制了在创build更多的承诺之前可以创build和解决的承诺的数量。 因此,在这种情况下,由于限制为1,它将创build第一个承诺,并且在达到限制时,将等待创build的Promise解决,然后继续下一个Promise。


如果使用calculate的整个点是延迟,那么我会推荐Promise.delay ,它可以像这样使用

 Promise.each(Object.keys(fileA), function (key) { return Promise.delay(500).then(function () { console.log(fileA[key]); }); }).then(function () { console.log('finish'); }); 

delay可以将Promise的parsing值透明地链接到下一个可用的函数,所以代码可以缩短到

 Promise.each(Object.keys(fileA), function (key) { return Promise.resolve(fileA[key]).delay(500).then(console.log); }).then(function () { console.log('finish'); }); 

由于Promise.delay接受一个dynamic值,所以你可以直接写成

 Promise.each(Object.keys(fileA), function (key) { return Promise.delay(fileA[key], 500).then(console.log); }).then(function () { console.log('finish'); }); 

如果Promise链本身在这里结束,那么最好使用.done()方法来标记它,就像这样

 ... }).done(function () { console.log('finish'); }); 

一般注意:如果你不打算在一个可用的函数中做任何处理,但是你只是用来跟踪进度或者跟随这个过程,那么你可以更好的将它们改为Promise.tap 。 所以,你的代码会变成

 Promise.each(Object.keys(fileA), function (key) { return Promise.delay(fileA[key], 500).tap(console.log); }).then(function () { // Do processing console.log('finish'); });