I have a function that takes an array of async/sync functions and invoke each of them sequentially (as opposed to in parallel) in the same order as the input is passed.
For example:
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 -> f3 -> f4
But now the return value of serializeAsyncFns
is a promise that resolves to the return value of the last function in the input list, which is f4
. Is there a way to tweak this funciton so that the returned promise resolves to the an array of values of all the functions, in order of how they got passed.
In this case it would be ['fn1', 'fn2', 'fn3', 'fn4']
Promise.all
doesn't work here as it would fire all the promises in parallel.
CodePudding user response:
easiest way is with a for loop and async/await
async function serializeAsyncFns(fns) {
const result = [];
for (const fn of fns) {
result.push(await fn());
}
return result;
}
If, for some reason you can't use async/await for that function, this is what I used to do before async/await was a thing
const serializeAsyncFns = fns =>
fns.reduce((promise, fn) =>
promise.then(results => Promise.resolve(fn()).then(result => [...results, result])),
Promise.resolve([])
);