使用 bluebird .reduce 将参数传递给一系列承诺

Passing arguments to a sequence of promises using bluebird .reduce

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

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

我最终使用了 Bluebird 的 promises 的 .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") 在使用

时按预期工作
return f1.then(f2);

但我不能全神贯注于如何保持异步计时,同时将参数传递给它。 预先感谢您的时间和帮助,在过去的 24 小时里,我一直在为此绞尽脑汁。

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

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

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中的"current"项,而是[=]的累加器的前一个值18=].


或者用简洁的箭头函数:

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