From f3568c7641df06bad075908805226d1b488b5897 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sat, 27 Mar 2021 22:14:58 +0100 Subject: [PATCH] working deadlyrace --- src/index.ts | 128 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 23 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9a0c512..16aec37 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import Emittery from "emittery"; +import { promisify } from "util"; //needed to pass information on wether or not the promise has been aborted witout 'this' class AbortableEmittery extends Emittery { @@ -10,33 +11,45 @@ class AbortableEmittery extends Emittery { } } -export default class AbortablePromise extends Promise { +export default class AbortablePromise implements PromiseLike { private emitter: AbortableEmittery; + private result_promise: Promise; + constructor( make_generator: ( - await_or_abort: ( - promise: Promise, - on_abort: () => Promise - ) => Promise + await_or_abort: ( + promise: Promise | AbortablePromise, + on_abort?: () => Promise | void + ) => Promise ) => AsyncGenerator ) { const emitter = new AbortableEmittery(); - const await_or_abort = ( - promise: Promise, - on_abort: () => Promise - ) => { + + function await_or_abort(promise: AbortablePromise): Promise; + function await_or_abort( + promise: Promise | AbortablePromise, + on_abort?: () => Promise | void + ): Promise { + if (promise instanceof AbortablePromise && !on_abort) { + on_abort = async () => promise.abort(); + } + if (on_abort === undefined) { + throw new Error( + "on_abort is required when the first argument is not AbortablePromise" + ); + } return new Promise((resolve, reject) => { let resolved = false; emitter.on("abort", () => { if (!resolved) { - on_abort(); - resolve(null); + (on_abort as Function)(); + reject(null); resolved = true; } }); promise - .then((result) => { + .then((result: L) => { if (!resolved) { resolve(result); resolved = true; @@ -44,10 +57,16 @@ export default class AbortablePromise extends Promise { }) .catch(reject); }); - }; - super(async (resolve, reject) => { + } + this.result_promise = new Promise(async (resolve, reject) => { let step_value; const generator = make_generator(await_or_abort); + console.log("generator:", generator, make_generator); + const e = new Error(); + if (!generator) { + console.error(e.stack); + console.log("generator:", generator); + } do { if (emitter.aborted) { resolve(null); @@ -63,21 +82,84 @@ export default class AbortablePromise extends Promise { abort() { this.emitter.abort(); } + + static deadlyRace(promises: AbortablePromise[]): Promise { + return new Promise((resolve) => { + let resolved = false; + const callback = (arg: L) => { + if (resolved) return; + resolved = true; + for (const promise of promises) { + console.log("one of the promises resolved! killing the others"); + promise.abort(); + } + resolve(arg); + }; + for (const promise of promises) { + promise.then(callback); + } + }); + } + + then( + onfulfilled?: + | ((value: T) => TResult1 | PromiseLike) + | undefined + | null, + onrejected?: + | ((reason: any) => TResult2 | PromiseLike) + | undefined + | null + ): PromiseLike { + const self = this; + return new AbortablePromise(async function* (await_or_abort) { + const ret = await await_or_abort(self.result_promise, () => { + self.abort(); + }); + yield; + if (onfulfilled) { + onfulfilled(ret); + } + }); + } } -// const sleep = promisify((timeout: number, callback: (...args: any[]) => void) => -// setTimeout(callback, timeout) -// ); +const sleep = promisify((timeout: number, callback: (...args: any[]) => void) => + setTimeout(callback, timeout) +); // const a = new AbortablePromise(async function* () { -// yield await sleep(1000); -// console.log("awaited 100"); -// yield await sleep(2000); -// console.log("awaited 200"); -// yield await sleep(3000); -// console.log("awaited 300"); +// yield await sleep(1000); +// console.log("awaited 100"); +// yield await sleep(2000); +// console.log("awaited 200"); +// yield await sleep(3000); +// console.log("awaited 300"); +// }); +// +// const a = new AbortablePromise(async function* () { +// yield await sleep(1000); +// console.log("awaited 100"); +// yield await sleep(2000); +// console.log("awaited 200"); +// yield await sleep(3000); +// console.log("awaited 300"); // }); +function abortableSleep(ms: number): AbortablePromise { + return new AbortablePromise(async function* () { + await sleep(ms); + yield; + console.log(`Slept ${ms}.`); + }); +} + +const b = AbortablePromise.deadlyRace([ + abortableSleep(1000), + abortableSleep(2000), + abortableSleep(3000), +]); + // setTimeout(() => a.abort(), 1500); // const b = new AbortablePromise(async function* (await_or_abort) {