- 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,
我需要循环只在每次超时完成后迭代一次,然后用完成后触发最后一次.
解决方法
- ...
- }).then(function (result) {
- console.log(result);
- console.log('finish');
- });
会打印
- [ 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对象,并且在解析了所有Promise之后调用带有finish的thenable函数.但它们都没有顺序解决.如果发生这种情况,将在指定的时间过后打印每个数字.这将我们带到第二部分.
>只要数组中的Promise被解析,> Promise.map
将执行作为参数传递的函数.引用文档,
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.
因此,数组中的所有值都将转换为Promises,并使用相应的值进行解析,并且将立即为每个值调用该函数.所以,他们都在同一时间等待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.
由于Promises是连续创建的,并且在继续之前等待分辨率,因此保证了结果的顺序.所以你的代码应该成为
- 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');
- });
并发选项基本上限制了在创建更多承诺之前可以创建和解决的Promises数量.因此,在这种情况下,由于限制为1,它将创建第一个承诺,并且当达到限制时,它将等到创建的Promise结算,然后转到下一个Promise.
如果使用计算的整个点是引入延迟,那么我会推荐Promise.delay
,可以像这样使用
- Promise.each(Object.keys(fileA),function (key) {
- return Promise.delay(500).then(function () {
- console.log(fileA[key]);
- });
- }).then(function () {
- console.log('finish');
- });
延迟可以透明地将Promise的已解析值链接到下一个可执行的函数,因此代码可以缩短为
- 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),500).tap(console.log);
- }).then(function () {
- // Do processing
- console.log('finish');
- });