import { isMicroQueue } from "./isMicroQueue.js"; const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected";
const isPromise = (obj) => !!(obj && typeof obj === "object" && typeof obj.then === "function");
class MyPromise { #state = PENDING; #value = undefined; #callbacks = []; constructor(executor) { try { executor(this.#resolve.bind(this), this.#reject.bind(this)); } catch (error) { this.#reject(error); throw error; } } #resolve(value) { this.#changeState(FULFILLED, value); } #reject(value) { this.#changeState(REJECTED, value); } #changeState(state, value) { if (!this.#isPending(this.#state)) return; this.#state = state; this.#value = value; this.#runCallbacks(); } #pushCallback(executor, state, resolve, reject) { this.#callbacks.push({ executor, state, resolve, reject, }); } #runCallbacks() { if (this.#isPending(this.#state)) return; while (this.#callbacks[0]) { const handler = this.#callbacks[0]; this.#runOneCallback(handler); this.#callbacks.shift(); } } #isPending(state) { return state === PENDING; }
#runOneCallback(callback) { isMicroQueue(() => { const { executor, state, resolve, reject } = callback; if (this.#state !== state) return; if (typeof executor !== "function") { this.#state === FULFILLED ? resolve(this.#value) : reject(this.#value); return; } try { const result = executor(this.#value); if (isPromise(result)) { result.then(resolve, reject); } else { resolve(result); } } catch (error) { reject(error); } }); } then(onFulfilled, onRejected) { return new MyPromise((resolve, reject) => { this.#pushCallback(onFulfilled, FULFILLED, resolve, reject); this.#pushCallback(onRejected, REJECTED, resolve, reject); this.#runCallbacks(); }); } catch(onRejected) { return this.then(undefined, onRejected); } finally(onFinally) { this.then( (val) => { onFinally(); return val; }, (err) => { onFinally(); throw err; } ); } static resolve(value) { if (value instanceof MyPromise) return value; return new MyPromise((resolve, reject) => { if (isPromise(value)) { value.then(resolve, reject); } else { resolve(value); } }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } static all(promises) { return new MyPromise((resolve, reject) => { try { const result = []; let count = 0; let fulfilledCount = 0; for (const item of promises) { let i = count; count++; MyPromise.resolve(item).then((res) => { result[i] = res; fulfilledCount++; if (fulfilledCount === count) { resolve(result); } }, reject); } if (count === 0) { resolve(result); } } catch (error) { reject(error); } }); } }
|