Last active
October 3, 2021 08:44
-
-
Save reosablo/7ea717bcefd2d3e267edb5e530e7301b to your computer and use it in GitHub Desktop.
Convert Promises to AsyncGenerator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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; | |
| } | |
| }; | |
| } | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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