Created
May 2, 2023 22:02
-
-
Save lichrot/efa68a587718dbf8c40cf962a0da5dbb to your computer and use it in GitHub Desktop.
Concurrency for Generator Functions, Promise style
This file contains 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
interface GeneratorFunction extends Function { | |
all: typeof all, | |
allSettled: typeof allSettled, | |
any: typeof any, | |
race: typeof race, | |
resolve: typeof resolve, | |
reject: typeof reject, | |
} | |
type GeneratorYieldType<TGenerator extends Generator> = TGenerator extends Generator<infer TYield, any, any> ? TYield : unknown; | |
type GeneratorReturnType<TGenerator extends Generator> = TGenerator extends Generator<any, infer TReturn, any> ? TReturn : unknown; | |
const GeneratorFunction = (function* () {}).constructor as GeneratorFunction; | |
GeneratorFunction.all = all; | |
GeneratorFunction.allSettled = allSettled; | |
GeneratorFunction.any = any; | |
GeneratorFunction.race = race; | |
GeneratorFunction.resolve = resolve; | |
GeneratorFunction.reject = reject; | |
function* all<TGenerator extends Generator>(generators: TGenerator[]) { | |
if (generators.length === 0) return []; | |
const results: GeneratorReturnType<TGenerator>[] = []; | |
while (results.length !== generators.length) { | |
for (let idx = 0; idx < generators.length; idx++) { | |
const result = generators[idx].next(); | |
if (result.done === true) results.push(result.value); | |
yield result.value as GeneratorYieldType<TGenerator>; | |
} | |
} | |
return results; | |
} | |
function* allSettled<TGenerator extends Generator>(generators: TGenerator[]) { | |
if (generators.length === 0) return []; | |
const results: GeneratorReturnType<TGenerator>[] = []; | |
while (results.length !== generators.length) { | |
for (let idx = 0; idx < generators.length; idx++) { | |
try { | |
const result = generators[idx].next(); | |
if (result.done === true) results.push(result.value); | |
yield result.value as GeneratorYieldType<TGenerator>; | |
} catch (error: any) { | |
results.push(error); | |
} | |
} | |
} | |
return results; | |
} | |
function* any<TGenerator extends Generator>(generators: TGenerator[]) { | |
if (generators.length === 0) throw Error(); | |
while (true) { | |
for (let idx = 0; idx < generators.length; idx++) { | |
const result = generators[idx].next(); | |
if (result.done === true) | |
return result.value as GeneratorReturnType<TGenerator>; | |
yield result.value as GeneratorYieldType<TGenerator>; | |
} | |
} | |
} | |
function* race<TGenerator extends Generator>(generators: TGenerator[]) { | |
if (generators.length === 0) throw Error(); | |
while (true) { | |
for (let idx = 0; idx < generators.length; idx++) { | |
try { | |
const result = generators[idx].next(); | |
if (result.done === true) | |
return result.value as GeneratorReturnType<TGenerator>; | |
yield result.value as GeneratorYieldType<TGenerator>; | |
} catch (error) { | |
return error; | |
} | |
} | |
} | |
} | |
function* resolve<T>(value: T): Generator<never, T, never> { | |
return value; | |
} | |
function* reject<TReason>(reason: TReason): Generator<never, never, never> { | |
throw reason; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment