Skip to content

Instantly share code, notes, and snippets.

@atengberg
Last active May 3, 2024 10:05
Show Gist options
  • Save atengberg/d29740421bf882d7e0b01cb55a670290 to your computer and use it in GitHub Desktop.
Save atengberg/d29740421bf882d7e0b01cb55a670290 to your computer and use it in GitHub Desktop.
Of all the eager settled promises.
/*
Always interesting when while working on a specific problem resolution,
coincidentally the circle gets squared. In this case, while building one thing,
it lead down the rabbit hole of async generators which surveyed everything from
https://www.dreamsongs.com/WorseIsBetter.html to https://okmij.org/ftp/Streams.html
and much, much more until it led back to an SO post that had a related SO post that
was quite literally almost the same thing I had originally set out to build (!).
I should probably compile all the bookmarks for any potential shared future benefit,
but note this particular generator function is almost *entirely* modeled on the work of Redu from:
https://stackoverflow.com/a/66751675/
where more background can be found:
https://betterprogramming.pub/why-would-you-use-async-generators-eabbd24c7ae6 */
/** Returns the resolved or rejected ("settled") value of each given promise in order of quickest to complete. */
function* EagerPromiseSequencer(promises) {
// These two are a ~JS "Jensen device" used to redirect invocation
// of each promise's settlement to caller's consumption.
let _RESOLVE, _REJECT;
// Expand each promise, linking the `resolve` and `reject` handlers to the generator's while-loop 'iteration'.
promises.forEach(p => p.then(v => _RESOLVE(v), e => _REJECT(e)));
// Let the generator yield a new promise for each of the given promises to pass the settled values to the caller.
while(true) yield new Promise((r,j) => [_RESOLVE, _REJECT] = [r,j]);
}
// Usage: (again, mostly directly copied from Redu's original code)
const promise = (val, delay, resolves) => new Promise((v,x) => setTimeout(() => resolves ? v(val) : x(val), delay));
const promises = [
promise("⎌1", 1000, true) ,
promise("⎌2", 2000, true),
promise("⎆3", 1500, false),
promise("⎆4", 3000, true)
];
const genEPS = EagerPromiseSequencer(promises);
async function sink() {
try {
for await (const value of genEPS) console.log(`Got: ${value}`);
} catch(err) {
console.log(`caught at endpoint --> exception ${err}`);
sink();
}
}
// note caller's for await should be wrapped as a function to recursively
// call when rejected error is pulled to continue iteration to completion. (see original SO)
sink();
/*>
Got: ⎌1
caught at endpoint --> exception ⎆3
Got: ⎌2
Got: ⎆4
*/
@kedicesur
Copy link

kedicesur commented May 3, 2024

I just noticed EcmaScript finally standardized exposing of resolve and reject by Promise.withResolvers() static method which is an important upgrade to the Promises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment