 # Composing asynchronous calls

#### 2021-05-13

Although I believe we often today navigate an asynchronous environment by forcing it to behave synchronously - kind of like stating “the worse for the facts” when a theory is proved flawed - it’s valuable to be able to create sequentially called (potentially) asynchronous functions.

As a step in understanding this process better, I’ve played with different ways of solving this problem. I wanted a logic handling latency between nodes in a sequence of function calls, a few synchronous (normalization, etc.), and some asynchronous (HTTP, DB requests, etc.). I also wanted to resolve a situation in which some steps require previous ones.

I made two variants of the same function. One allowing you the chain functions, and an implementation of ‘compose’ - both permitting asynchronous calls.

This my expected output, aiming to in mock something close-enough a real scenario.

[ 1, 2, 3 ]       → initial value
[ 2, 4, 6 ]       → doubled
[ 3, 5, 7 ]       → 2s later, increased by one
[ 4, 6, 8 ]       → 2s later, increased by one
[ 8, 12, 16 ]     → doubled
Result: [9,13,17] → 2s later, increased by one


# A ‘thenable’ solution

const inc = (x) => x + 1;

const double = (x) => x + x;

const doubleList = (xs) => xs.map(double);

const fakeRequest = (xs) =>
new Promise((resolve) => setTimeout(() => resolve(xs.map(inc)), 2000));

class SequentialPromises {
constructor(x) {
this.x = x;
}

async then(fn) {
const v = await fn(this.x);
return this.x === undefined ? v : new SequentialPromises(v);
}
}

const trace = (fn) => (x) => {
console.log(x);
return fn(x);
};

const seqChain = async (initialValue) => {
const result = await new SequentialPromises(initialValue)
.then(trace(doubleList))
.then(trace(fakeRequest))
.then(trace(fakeRequest))
.then(trace(doubleList))
.then(trace(fakeRequest));
console.log(Result: [${result}]); }; seqChain([1, 2, 3]);  # …using compose const compose = (...fns) => async (v) => { for (let i = fns.length - 1; i >= 0; i--) { v = await fns[i](v); } return v; }; const asyncCompose = async (initialValue) => { const result = await compose( trace(fakeRequest), trace(doubleList), trace(fakeRequest), trace(fakeRequest), trace(doubleList) )(initialValue); console.log(Result: [${result}]);
};
asyncCompose([1, 2, 3]);