如何修改JavaScript串行异步函数方法以按序返回所有执行结果?
问题
我有一个接收异步/同步函数数组的方法,它会按照输入顺序串行(而非并行)调用每个函数。示例代码如下:
const sleep = (delay) => new Promise((r) => setTimeout(r, delay)) const fn1 = async () => { await sleep(2000) console.log('fn1') return 'fn1' } const fn2 = async () => { await sleep(3000) console.log('fn2') return 'fn2' } const fn3 = async () => { await sleep(1000) console.log('fn3') return 'fn3' } const fn4 = () => { console.log('fn4') return 'fn4' } function serializeAsyncFns(fns) { return fns.reduce( (promise, fn) => promise.then(() => fn()), Promise.resolve() ) } serializeAsyncFns([fn1, fn2, fn3, fn4]) // fn1 -> fn2 -> fn3 -> fn4
但当前serializeAsyncFns返回的Promise仅会解析为输入列表中最后一个函数的返回值,即fn4。能否修改该方法,使其返回的Promise解析为所有函数的返回值组成的数组,且顺序与输入顺序一致?例如返回['fn1', 'fn2', 'fn3', 'fn4']。
Promise.all无法满足需求,因为它会并行触发所有Promise。
解决方案
只需要在累积过程中保存每一步的返回值即可,修改后的serializeAsyncFns函数如下:
function serializeAsyncFns(fns) { return fns.reduce( (promise, fn) => promise.then(results => { const result = fn(); // 统一处理同步/异步函数的返回值,确保以Promise形式处理 return Promise.resolve(result).then(res => [...results, res]); }), Promise.resolve([]) ) }
说明
- 初始累积值改为
Promise.resolve([]),即以空数组作为结果的起点; - 在
then回调中,先获取已有的结果数组results,调用目标函数后将返回值转为Promise(兼容同步函数的直接返回值),再把新结果追加到数组末尾; - 最终返回的Promise会解析为按调用顺序排列的所有函数返回值数组。
调用修改后的函数:serializeAsyncFns([fn1, fn2, fn3, fn4]).then(console.log),会输出['fn1', 'fn2', 'fn3', 'fn4'],同时保持原有的串行执行顺序。
内容的提问来源于stack exchange,提问作者Joji
相关产品推荐
相关产品推荐

