Skip to content

Instantly share code, notes, and snippets.

@reosablo
Last active October 3, 2021 08:44
Show Gist options
  • Select an option

  • Save reosablo/7ea717bcefd2d3e267edb5e530e7301b to your computer and use it in GitHub Desktop.

Select an option

Save reosablo/7ea717bcefd2d3e267edb5e530e7301b to your computer and use it in GitHub Desktop.
Convert Promises to AsyncGenerator
/**
* combine promises into an async generator in order of fast resolved
* @param promises promises to output
*/
export async function* toAsyncGenerator<T>(promises: Iterable<Promise<T>>) {
const unresolvedPromises = new Set(promises);
const fulfilledValues: T[] = [];
for (const promise of promises) {
promise.then(
(value) => {
unresolvedPromises.delete(promise);
fulfilledValues.push(value);
},
(_) => {}
);
}
yield* {
[Symbol.asyncIterator]() {
return {
async next() {
if (unresolvedPromises.size + fulfilledValues.length > 0) {
if (fulfilledValues.length === 0) {
await Promise.race(unresolvedPromises);
}
return {
value: fulfilledValues.shift()!,
done: false
};
}
return { done: true } as const;
}
};
}
};
}
import { toAsyncGenerator } from "./to-async-generator";
// make Promise from setTimeout
async function deferredMessage(duration: number, mode?: "reject") {
return await new Promise<string>((resolve, reject) =>
setTimeout(
mode !== "reject"
? () => resolve(`fulfilled in ${duration}ms`)
: () => reject(`rejected in ${duration}ms`),
duration
);
);
}
// shuffle array destructively
function shuffle<T>(target: T[]) {
const copy = [...target];
target.length = 0;
while (copy.length > 0) {
target.push(...copy.splice((Math.random() * copy.length) | 0, 1));
}
}
// params for deferredMessage function
const params = [
[1000],
[2000],
[3000],
[4000],
[4500, "reject"],
[5000] // <- "fulfilled in 5000ms" will not be displayed
] as Parameters<typeof deferredMessage>[];
// shuffle params
shuffle(params);
console.log("shuffled parameters: %o", params);
// make promises from params
const promises = params.map((param) => deferredMessage(...param));
(async () => {
// expected output
// fulfilled in 1000ms
// fulfilled in 2000ms
// fulfilled in 3000ms
// fulfilled in 4000ms
// rejected in 4500ms
try {
for await (const message of toAsyncGenerator(promises)) {
console.log(message);
}
} catch (error) {
console.error(error);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment