working deadlyrace

master
Kuba Orlik 4 years ago
parent ee3d998c08
commit f3568c7641

@ -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<T> extends Promise<T | null> {
export default class AbortablePromise<T> implements PromiseLike<T> {
private emitter: AbortableEmittery;
private result_promise: Promise<T>;
constructor(
make_generator: (
await_or_abort: (
promise: Promise<any>,
on_abort: () => Promise<unknown>
) => Promise<unknown>
await_or_abort: <L>(
promise: Promise<L> | AbortablePromise<L>,
on_abort?: () => Promise<unknown> | void
) => Promise<L>
) => AsyncGenerator
) {
const emitter = new AbortableEmittery();
const await_or_abort = (
promise: Promise<any>,
on_abort: () => Promise<unknown>
) => {
function await_or_abort<L = any>(promise: AbortablePromise<L>): Promise<L>;
function await_or_abort<L = any>(
promise: Promise<L> | AbortablePromise<L>,
on_abort?: () => Promise<unknown> | void
): Promise<L> {
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<T> extends Promise<T | null> {
})
.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<T> extends Promise<T | null> {
abort() {
this.emitter.abort();
}
static deadlyRace<L>(promises: AbortablePromise<L>[]): Promise<L> {
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<TResult1 = T, TResult2 = never>(
onfulfilled?:
| ((value: T) => TResult1 | PromiseLike<TResult1>)
| undefined
| null,
onrejected?:
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
| undefined
| null
): PromiseLike<TResult1 | TResult2> {
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<void> {
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) {

Loading…
Cancel
Save