Skip to content

Instantly share code, notes, and snippets.

@FaberVitale
Created October 30, 2023 10:28
Show Gist options
  • Save FaberVitale/d8035c70af2cb6d6cb32a80b1673ed06 to your computer and use it in GitHub Desktop.
Save FaberVitale/d8035c70af2cb6d6cb32a80b1673ed06 to your computer and use it in GitHub Desktop.
A partial Ecmascript promise implementation written in typescript
type InnerPromise2State<T> =
| {
type: "idle";
}
| { type: "resolved"; value: T }
| { type: "rejected"; error: unknown };
type Consumer<T> = (value: T) => void;
type Promise2Executor<T> = (
resolve: Consumer<T>,
reject: Consumer<unknown>,
) => unknown;
type CatchCallback = (value: any) => unknown;
type OkCallback<T> = (value: T) => unknown;
export class Promise2<T> {
#state: InnerPromise2State<T> = { type: "idle" };
#listenersOk: OkCallback<T>[] = [];
#listenersErr: CatchCallback[] = [];
constructor(task: Promise2Executor<T>) {
try {
task(this.#resolve.bind(this), this.#reject.bind(this));
} catch (err) {
this.#reject(err);
}
}
#resolve(value: T): void {
if (this.#state.type === "idle") {
this.#state = { type: "resolved", value };
this.#verifyState();
}
}
#reject(error: unknown): void {
if (this.#state.type === "idle") {
this.#state = { type: "rejected", error };
this.#verifyState();
}
}
#verifyState() {
switch (this.#state.type) {
case "idle":
break;
case "resolved": {
this.#listenersOk.forEach((listener) =>
queueMicrotask(() =>
listener((this.#state as { type: "resolved"; value: T }).value),
),
);
break;
}
case "rejected": {
this.#listenersErr.forEach((listener) =>
queueMicrotask(() =>
listener(
(this.#state as { type: "rejected"; error: unknown }).error,
),
),
);
break;
}
}
if (this.#state.type !== "idle") {
this.#listenersErr.splice(0, this.#listenersErr.length);
this.#listenersOk.splice(0, this.#listenersOk.length);
}
}
then(okCb: OkCallback<T>, errCb?: ErrorCallback) {
this.#listenersOk.push(okCb);
if (errCb) {
this.#listenersErr.push(errCb);
}
this.#verifyState();
}
catch(cb: ErrorCallback) {
this.#listenersErr.push(cb);
this.#verifyState();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment