我希望用蓝鸟循环完成一些任务,只需使用超时作为实验机制。 [不希望使用异步或任何其他库]
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,
我需要循环只在每次超时完成后迭代一次,然后用完成后触发最后一次。
答案 0 :(得分:15)
在传递给Promise.map
的函数对象中,需要返回一个Promise对象,以便解析所有Promises,并将已解析值的数组传递给下一个{{1功能。在您的情况下,由于您未明确返回任何内容,因此默认情况下将返回then
,而不是承诺。因此,当undefined
的承诺通过finish
s解析时,Promises.map
的可执行函数将被执行。您可以像这样确认
undefined
会打印
...
}).then(function (result) {
console.log(result);
console.log('finish');
});
因此,您的代码应该有[ undefined, undefined, undefined, undefined, undefined ]
finish
one
two
three
four
five
这样的语句
return
现在,您将看到代码按顺序打印事物,因为我们返回Promise对象,并且在解析了所有Promise之后调用带有Promise.map(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
的thenable函数。但它们都没有顺序解决。如果发生这种情况,将在指定的时间过后打印每个数字。这将我们带到第二部分。
Promise.map
将执行作为参数传递的函数。引用文档,
尽快调用给定项的映射器函数,也就是说,当满足输入数组中该项的索引的承诺时。
因此,数组中的所有值都将转换为Promises,并使用相应的值进行解析,并且将立即为每个值调用该函数。所以,他们都在同一时间等待500毫秒并立即解决。这不会按顺序发生。
由于您希望它们按顺序执行,因此您需要使用Promise.each
。引用文档,
迭代连续发生。 ....如果迭代器函数返回promise或者thenable,则在继续下一次迭代之前等待promise的结果。
由于Promises是连续创建的,并且在继续之前等待分辨率,因此保证了结果的顺序。所以你的代码应该成为
finish
附加说明:
如果订单无关紧要,正如Benjamin Gruenbaum所建议的那样,您可以使用Promise.each(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
本身,concurrency
limit,就像这样
Promise.map
Promise.map(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}, { concurrency: 1 }).then(function () {
console.log('finish');
});
选项基本上限制了在创建更多承诺之前可以创建和解决的Promises数量。因此,在这种情况下,由于限制为1,它将创建第一个承诺,当达到限制时,它将等到创建的Promise结算,然后转到下一个Promise。
如果使用concurrency
的全部内容是引入延迟,那么我会推荐Promise.delay
,可以像这样使用
calculate
Promise.each(Object.keys(fileA), function (key) {
return Promise.delay(500).then(function () {
console.log(fileA[key]);
});
}).then(function () {
console.log('finish');
});
可以透明地将Promise的已解析值链接到下一个可执行的函数,因此代码可以缩短为
delay
由于Promise.delay
接受动态值,因此您可以简单地将其写为
Promise.each(Object.keys(fileA), function (key) {
return Promise.resolve(fileA[key]).delay(500).then(console.log);
}).then(function () {
console.log('finish');
});
如果Promise链本身就此结束,最好使用.done()
方法来标记它,就像这样
Promise.each(Object.keys(fileA), function (key) {
return Promise.delay(fileA[key], 500).then(console.log);
}).then(function () {
console.log('finish');
});
一般注意事项:如果您不打算在一个可执行的功能中进行任何处理,但是您只是为了跟踪进度或跟踪该过程,那么您可以更好地将它们更改为{ {3}}。所以,你的代码将成为
...
}).done(function () {
console.log('finish');
});