Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 1x 1x 112x 112x 112x 112x 112x 71x 25x 3x 3x 71x 71x 71x 25x 25x 25x 71x 40x 2x 2x 38x 38x 36x 4x 32x 2x 71x 25x 7x 7x 18x 18x 17x 4x 13x 1x 71x 30x 30x 30x 25x 25x 16x 16x 9x 4x 1x 3x 15x 12x 1x 3x 3x 3x 3x 1x 3x 3x 3x 3x 2x | type Callback = (value?: any) => any;
const nextTick = globalThis.queueMicrotask || process.nextTick;
export class Promise {
private state = "pending" as "pending" | "resolved" | "rejected";
private value: any;
private error: any;
private pendThen: Callback[] = [];
private pendCatch: Callback[] = [];
static resolve: Callback;
static reject: Callback;
static all: (promises: Promise[]) => void;
constructor(
fn: (res: Promise["resolveValue"], rej: Promise["rejectValue"]) => void
) {
try {
fn(
// TODO resolve promise
(val) => this.resolveValue(val),
(e) => this.rejectValue(e)
);
} catch (error) {
this.state = "rejected";
this.error = error;
}
}
private resolveValue(val?: any) {
this.state = "resolved";
this.value = val;
this.pendThen.forEach((fn) => fn(val));
}
private rejectValue(e?: any) {
this.state = "rejected";
this.error = e;
this.pendCatch.forEach((fn) => fn(e));
}
then(resFn?: Callback, rejFn?: Callback): Promise {
const baseResolve = (res: Callback, rej: Callback) => {
if (!resFn) {
res(this.value);
return;
}
try {
const resVal = resFn(this.value);
if (typeof resVal?.then === "function") {
resVal.then((v: any) => res(v));
} else {
res(resVal);
}
} catch (error) {
rej(error);
}
};
const baseReject = (res: Callback, rej: Callback) => {
if (!rejFn) {
rej(this.error);
return;
}
try {
const resVal = rejFn(this.error);
if (typeof resVal?.then === "function") {
resVal.then(res, rej);
} else {
res(resVal);
}
} catch (error) {
rej(error);
}
};
switch (this.state) {
case "pending":
// defer run after this promise resolved
return new Promise((res, rej) => {
this.pendThen.push(() => baseResolve(res, rej));
this.pendCatch.push(() => baseReject(res, rej));
});
case "resolved":
return new Promise((res, rej) =>
// run at next tick
nextTick(() => baseResolve(res, rej))
);
case "rejected":
return new Promise((res, rej) =>
// run at next tick
nextTick(() => baseReject(res, rej))
);
/* istanbul ignore next */
default:
throw new Error("Unknown promise state: " + this.state);
}
}
catch(rejFn: Callback) {
return this.then(undefined, rejFn);
}
finally(fn: Callback) {
return this.then(
(v) => {
Promise.resolve(fn()).then(() => v);
},
(v) => Promise.resolve(fn()).then(() => Promise.reject(v))
);
}
}
Promise.resolve = (val?: any) => new Promise((res) => res(val));
Promise.reject = (e?: any) => new Promise((_, rej) => rej(e));
Promise.all = (promises) => {
const len = promises.length;
let cnt = 0;
return new Promise((res) => {
if (!len) {
res();
}
promises.forEach((promise) =>
promise.then(() => {
cnt++;
if (cnt === len) {
res();
}
})
);
});
};
|