Skip to content

Instantly share code, notes, and snippets.

@lichrot
Created May 2, 2023 22:02
Show Gist options
  • Save lichrot/efa68a587718dbf8c40cf962a0da5dbb to your computer and use it in GitHub Desktop.
Save lichrot/efa68a587718dbf8c40cf962a0da5dbb to your computer and use it in GitHub Desktop.
Concurrency for Generator Functions, Promise style
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