Skip to content

Home

Asynchronous function composition in JavaScript

If you're familiar with function composition, you might have wondered how to compose asynchronous functions in JavaScript. While not exactly as simple, the underlying principles are the same.

Pipe async functions

Left-to-right function composition for asynchronous functions can be achieved by using Array.prototype.reduce() and the spread operator (...) to perform function composition using Promise.prototype.then().

The functions can return a combination of normal values, Promises, or be async, returning through await. All functions must accept a single argument.

const pipeAsync =
  (...fns) =>
  arg =>
    fns.reduce((p, f) => p.then(f), Promise.resolve(arg));

const sum = pipeAsync(
  x => x + 1,
  x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)),
  x => x + 3,
  async x => (await x) + 4
);
(async () => {
  console.log(await sum(5)); // 15 (after one second)
})();

Compose async functions

Right-to-left function compositions for asynchronous functions can be achieved by using the lesser-used Array.prototype.reduceRight() in place of Array.prototype.reduce(). The rest of the implementation is the same.

const composeAsync =
  (...fns) =>
  arg =>
    fns.reduceRight((p, f) => p.then(f), Promise.resolve(arg));

const sum = composeAsync(
  async x => (await x) + 4,
  x => x + 3,
  x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)),
  x => x + 1
);
(async () => {
  console.log(await sum(5)); // 15 (after one second)
})();

More like this

Start typing a keyphrase to see matching snippets.