【问题标题】:Passing arguments to a sequence of promises using bluebird .reduce使用 bluebird .reduce 将参数传递给一系列 Promise
【发布时间】:2018-04-09 11:50:53
【问题描述】:

我发现了很多减少相关问题的承诺,但没有什么能对我的特定问题有帮助,所以如果我最终错过了与我的问题的联系,这可能对其他人来说很明显。

简而言之:我有一个节点脚本需要对一堆不同的文件进行链式操作,这些操作是异步的,包装在 Promise 中,但最终出于各种原因,我希望文件处理按顺序进行。

我最终使用了 Bluebird 的 Promise 的 .reduce 功能来做到这一点,但我无法理解我应该如何将参数传递给它。

以下简化示例总结了我的问题的核心:

const Promise = require('bluebird');

var f = (string) => {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(string);
            resolve();
        }, 3000);
    })
    .catch(err => {
        console.error(err);
    });
};

var strings = ["hello", "world"];

strings.reduce((current, next) => {
    return f(current).then(f(next));
}, Promise.resolve([]))
.then(() => {
    console.log("All done!");
})
.catch(err => {
    console.error(err);
});

我所期望的以及我需要脚本做的是让它在一组参数上按顺序执行承诺。 我得到以下输出:

hello // after 3s
world // after 3s
All done! // after 3s

我想要的是:

hello // after 3s
world // after 6s
All done! // after 6s

我知道问题是承诺在创建后立即执行,并且我正在使用 f(next) 在创建第一个实例的同时创建第二个实例.

我也知道使用不带参数的承诺,即带有硬编码 console.log("hello") 的 f1 和带有硬编码 console.log("world") 的 f2 使用时按预期工作

return f1.then(f2);

但是我不知道如何在保持异步时序的同时将参数传递给它。 提前感谢您的时间和帮助,在过去的 24 小时里,我一直在为这个问题摸不着头脑。

【问题讨论】:

    标签: javascript node.js bluebird


    【解决方案1】:

    您在每次迭代中对 f 进行 两次 调用,您只需要一次,并且您希望您所做的一次等待前一个承诺得到解决 - 所以你可以' t 做.then(f(next)) 因为这不会等待,您需要传入一个函数。 (另外,由于你从不使用第一个 Promise 的分辨率值,所以不需要给它一个空数组。)

    因此进行两项更改(一次调用,并传入一个函数):

    strings.reduce((p, next) => {        // ***
        return p.then(() => f(next));    // *** Main changes here
    }, Promise.resolve())                // ***
    .then(() => {
        console.log("All done!");
    })
    .catch(err => {
        console.error(err);
    });
    

    实时示例(超时时间更短):

    var f = (string) => {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(string);
                resolve();
            }, 1000);
        })
        .catch(err => {
            console.error(err);
        });
    };
    
    var strings = ["hello", "world"];
    
    strings.reduce((p, next) => {        // ***
        return p.then(() => f(next));    // *** Main changes here
    }, Promise.resolve([]))              // ***
    .then(() => {
        console.log("All done!");
    })
    .catch(err => {
        console.error(err);
    });

    我还重命名了current参数p,因为它不是strings中的“当前”条目,而是reduce的累加器的先前值。


    或者用简洁的箭头函数:

    strings.reduce((p, next) => p.then(() => f(next)), Promise.resolve())
    .then(() => {
    // ...
    

    【讨论】:

    • 非常感谢,您的回答解决了我的问题:我还没有完全理解累加器与我的迭代有什么关系,您的解释帮助很大!
    • @SpicySquidInk:很高兴有帮助!旁注:我们可以使用上面箭头函数的简洁形式:strings.reduce((p, next) => p.then(() => f(next)), Promise.resolve())(另请注意,不需要将空数组传递给Promise.resolve)。
    猜你喜欢
    • 2012-09-05
    • 2016-05-20
    • 2013-12-13
    • 2017-07-11
    • 2016-11-18
    • 2011-08-11
    • 1970-01-01
    • 2017-06-10
    相关资源
    最近更新 更多