Skip to content

Instantly share code, notes, and snippets.

@NyanHelsing
Last active April 19, 2025 14:30
Show Gist options
  • Save NyanHelsing/798f6122ffb17ac0f763d63ca0b6708d to your computer and use it in GitHub Desktop.
Save NyanHelsing/798f6122ffb17ac0f763d63ca0b6708d to your computer and use it in GitHub Desktop.
WaitLift
/**
* curryFlip(fn) takes a two-argument function `fn` and returns
* a curried function that applies `fn` with its arguments reversed.
*/
const curryFlip = (fn) => a => b => fn(b, a);
/**
* Returns an array of promises (or values) where each item
* is [key, await transform(value)].
*/
function createAsyncEntriesTransformer(asyncStrategy) {
return async function asyncEntriesTransformer(obj, transform) {
const entryTransform = async ([key, value]) =>
[key, await transform(await value)];
const entriesToTransform = Object.entries(obj);
const transformingEntries = entriesToTransform.map(entryTransform);
const strategyResolution = asyncStrategy(transformingEntries);
return Object.fromEntries(await strategyResolution);
};
}
// Now we can reuse createTransformedPairs in allEntries and allEntriesSettled:
/**
* allEntries(iterable, transform):
* - transforms each value in parallel
* - rejects on the first failed transform
* - returns final object
*/
const allEntries = createAsyncEntriesTransformer(_ => Promise.all(_));
/**
* allEntriesSettled(iterable, transform):
* - transforms each value in parallel
* - never rejects, always resolves with final object
* - for each rejection, place the reason at that key
*/
const allEntriesSettled = createAsyncEntriesTransformer(_ => Promise.allSettled(_));
/**
* liftAllEntries(iterable, transform):
* Takes an async function and returns a function that
* can be applied to the values of an object, transforming
* each value in parallel.
*/
export const liftPromiseAllEntries = curryFlip(allEntries);
/**
* liftAllEntriesSettled(iterable, transform):
* Takes an async function and returns a function that
* can be applied to an object, transforming each value in parallel,
* and returning a promise that resolves to an object with
* the same keys, where each value is the settlement of the
* corresponding promise.
*/
export const liftPromiseAllEntriesSettled = curryFlip(allEntriesSettled);
// ----------------------------------------------------------------------------
// I don't care I'm gonna do it anyway
Object.defineProperty(Promise, 'allEntries', {
value: function (iterable) {
return allEntries(iterable, (x) => x); // identity transform
},
writable: true,
configurable: true
});
Object.defineProperty(Promise, 'allEntriesSettled', {
value: function (iterable) {
return allEntriesSettled(iterable, (x) => x); // identity transform
},
writable: true,
configurable: true
});
const promiseValue = (value, time) => {
const { promise, resolve } = Promise.withResolvers();
setTimeout(() => resolve(value), time)
return promise;
}
const {
myValue,
otherValue
} = liftPromiseAllEntries((resolved) => resolved * 2)({
myValue: promiseValue(42, 100),
otherValue: promiseValue(666, 1000)
})
console.log(myValue) // logs 84
console.log(otherValue) // logs 1336
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment