HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

Asynchronous function composition in JavaScript

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
functionjavascriptcompositionasynchronous

Problem

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.
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.
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.

Solution

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)
})();


The functions can return a combination of normal values, Promises, or be async, returning through await. All functions must accept a single argument.
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.

Code Snippets

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)
})();
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)
})();

Context

From 30-seconds-of-code: async-function-composition

Revisions (0)

No revisions yet.