使用 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(() => {
// ...
我发现很多减少相关问题的承诺,但没有什么能完全帮助我解决我的特定问题,所以如果我最终错过了与我的问题的联系,这对其他人来说可能很明显,请提前原谅。
简而言之:我有一个节点脚本需要对一堆不同的文件进行链式操作,这些操作是异步的,包装在承诺中,但最终由于各种原因我希望文件处理按顺序进行。
我最终使用了 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(() => {
// ...