循环通过任务瀑布 – 承诺蓝鸟
我正在寻找循环通过蓝鸟一些任务,只是使用超时作为实验机制。 [不希望使用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,
我需要循环只遍历每个超时完成,然后发射最后一个完成。
-
在传递给
Promise.map
的函数对象中,您需要返回一个Promise对象,以便所有的Promise将被parsing,并且parsing值的数组可以传递到下一个函数。 在你的情况下,因为你没有明确地返回任何东西,undefined
将被返回,默认情况下,不是一个承诺。 因此,当Promise.map中的Promises.map
被parsing为undefined
,finish
的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对象,并在所有Promiseparsing
finish
后调用可执行的finish
函数。 但是他们都没有顺序解决。 如果发生这种情况,在指定的时间过后,每个数字都会被打印出来。 这将我们带到第二部分。 -
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'); });