javascript – 循环任务瀑布 – 承诺蓝鸟

我正在寻找蓝鸟的一些任务,只是使用超时作为实验机制. [不希望使用异步或任何其他库]
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对象,以便解析所有Promises,并将已解析值的数组传递给下一个函数.在您的情况下,由于您没有显式返回任何内容,因此认情况下将返回undefined,而不是promise.因此,当使用undefineds解析Promises.map的Promises时,执行带有finish的thenable函数.你可以这样确认一下
...
}).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');
});

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...