import Emittery from "emittery"; //needed to pass information on wether or not the promise has been aborted witout 'this' class AbortableEmittery extends Emittery { public aborted = false; abort() { this.aborted = true; this.emit("abort"); } } export default class AbortablePromise extends Promise { private emitter: AbortableEmittery; constructor( make_generator: ( await_or_abort: ( promise: Promise, on_abort: () => Promise ) => Promise ) => AsyncGenerator ) { const emitter = new AbortableEmittery(); const await_or_abort = ( promise: Promise, on_abort: () => Promise ) => { return new Promise((resolve, reject) => { let resolved = false; emitter.on("abort", () => { if (!resolved) { on_abort(); resolve(null); resolved = true; } }); promise .then((result) => { if (!resolved) { resolve(result); resolved = true; } }) .catch(reject); }); }; super(async (resolve, reject) => { let step_value; const generator = make_generator(await_or_abort); do { if (emitter.aborted) { resolve(null); return; } step_value = await generator.next(); } while (!step_value.done); resolve(step_value.value); }); this.emitter = emitter; } abort() { this.emitter.abort(); } } // 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"); // }); // setTimeout(() => a.abort(), 1500); // const b = new AbortablePromise(async function* (await_or_abort) { // const ping = await deferedSpawn("ping", ["8.8.8.8"]); // while (true) { // console.log( // await await_or_abort(ping.waitForNextData(), () => { // ping.kill(); // }) // ); // yield; // } // }); // setTimeout(() => b.abort(), 5000);