循环遍历任务瀑布- promises bluebird
Loop through tasks waterfall- promises bluebird
我希望使用 bluebird 循环执行一些任务,只是将超时用作实验机制。 [不打算使用异步或任何其他库]
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,
我需要循环在每次超时完成时只迭代一次,然后在完成时触发最后一个 thenable。
在传递给Promise.map
的函数对象中,需要return一个Promise对象,这样所有的Promises都会被resolved,并且resolved值的数组可以传递给下一个 then
函数。在您的情况下,由于您没有明确 returning 任何内容,因此默认情况下 undefined
将被 returned,而不是承诺。因此,finish
的 thenable 函数被执行,因为 Promises.map
的 Promise 被 undefined
解决了。你可以这样确认
...
}).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');
});
现在,您将看到代码按顺序打印事物,因为我们 return Promise 对象和带有 finish
的 thenable 函数在所有 Promise 被解决后被调用。但它们都没有按顺序解决。如果发生这种情况,每个数字都会在指定的时间过去后打印出来。这就把我们带到了第二部分。
Promise.map
将执行作为参数传递的函数,一旦数组中的 Promises 被解析。引用文档,
The mapper function for a given item is called as soon as possible, that is, when the promise for that item's index in the input array is fulfilled.
因此,数组中的所有值都被转换为 Promise,并使用相应的值进行解析,并且将立即为每个值调用该函数。因此,他们都同时等待 500 毫秒并立即解决。这不会按顺序发生。
既然要它们顺序执行,就需要用到Promise.each
。引用文档,
Iteration happens serially. .... If the iterator function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration.
由于 Promise 是连续创建的,并且在继续之前等待解决,因此结果的顺序是有保证的。所以你的代码应该变成
Promise.each(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
补充说明:
如果顺序无关紧要,正如 Benjamin Gruenbaum 所建议的,您可以使用 Promise.map
本身和 concurrency
limit,像这样
Promise.map(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}, { concurrency: 1 }).then(function () {
console.log('finish');
});
concurrency
选项基本上限制了在创建更多承诺之前可以创建和解决的承诺数量。因此,在这种情况下,由于限制为 1,它将创建第一个承诺,并且当达到限制时,它将等到创建的 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 的 resolved 值链接到下一个 thenable 函数,因此代码可以缩短为
Promise.each(Object.keys(fileA), function (key) {
return Promise.resolve(fileA[key]).delay(500).then(console.log);
}).then(function () {
console.log('finish');
});
由于Promise.delay
接受一个动态值,你可以简单地写成
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');
});
我希望使用 bluebird 循环执行一些任务,只是将超时用作实验机制。 [不打算使用异步或任何其他库]
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,
我需要循环在每次超时完成时只迭代一次,然后在完成时触发最后一个 thenable。
在传递给
Promise.map
的函数对象中,需要return一个Promise对象,这样所有的Promises都会被resolved,并且resolved值的数组可以传递给下一个then
函数。在您的情况下,由于您没有明确 returning 任何内容,因此默认情况下undefined
将被 returned,而不是承诺。因此,finish
的 thenable 函数被执行,因为Promises.map
的 Promise 被undefined
解决了。你可以这样确认... }).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'); });
现在,您将看到代码按顺序打印事物,因为我们 return Promise 对象和带有
finish
的 thenable 函数在所有 Promise 被解决后被调用。但它们都没有按顺序解决。如果发生这种情况,每个数字都会在指定的时间过去后打印出来。这就把我们带到了第二部分。Promise.map
将执行作为参数传递的函数,一旦数组中的 Promises 被解析。引用文档,The mapper function for a given item is called as soon as possible, that is, when the promise for that item's index in the input array is fulfilled.
因此,数组中的所有值都被转换为 Promise,并使用相应的值进行解析,并且将立即为每个值调用该函数。因此,他们都同时等待 500 毫秒并立即解决。这不会按顺序发生。
既然要它们顺序执行,就需要用到
Promise.each
。引用文档,Iteration happens serially. .... If the iterator function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration.
由于 Promise 是连续创建的,并且在继续之前等待解决,因此结果的顺序是有保证的。所以你的代码应该变成
Promise.each(Object.keys(fileA), function (key) { return calculate(key).then(function (res) { console.log(res); }); }).then(function () { console.log('finish'); });
补充说明:
如果顺序无关紧要,正如 Benjamin Gruenbaum 所建议的,您可以使用
Promise.map
本身和concurrency
limit,像这样Promise.map(Object.keys(fileA), function (key) { return calculate(key).then(function (res) { console.log(res); }); }, { concurrency: 1 }).then(function () { console.log('finish'); });
concurrency
选项基本上限制了在创建更多承诺之前可以创建和解决的承诺数量。因此,在这种情况下,由于限制为 1,它将创建第一个承诺,并且当达到限制时,它将等到创建的 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 的 resolved 值链接到下一个 thenable 函数,因此代码可以缩短为
Promise.each(Object.keys(fileA), function (key) {
return Promise.resolve(fileA[key]).delay(500).then(console.log);
}).then(function () {
console.log('finish');
});
由于Promise.delay
接受一个动态值,你可以简单地写成
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');
});