/** * Synchronous Promise Implementation * * Custom Promise implementation that executes synchronously when possible * Useful for testing and scenarios requiring deterministic execution order */ const PromiseState = { PENDING: 0, RESOLVED: 1, REJECTED: 2, }; /** * Synchronous Promise implementation */ class SyncPromise { constructor(executor) { this._state = PromiseState.PENDING; this._handlers = []; this._value = undefined; // Bind methods to preserve context this._resolve = this._resolve.bind(this); this._reject = this._reject.bind(this); this._setResult = this._setResult.bind(this); this._executeHandlers = this._executeHandlers.bind(this); try { executor(this._resolve, this._reject); } catch (error) { this._reject(error); } } /** * Promise then method * @param {Function} onFulfilled - Success handler * @param {Function} onRejected - Error handler * @returns {SyncPromise} New promise */ then(onFulfilled, onRejected) { return new SyncPromise((resolve, reject) => { this._handlers.push([ false, // not executed yet (value) => { if (!onFulfilled) { resolve(value); } else { try { resolve(onFulfilled(value)); } catch (error) { reject(error); } } }, (reason) => { if (!onRejected) { reject(reason); } else { try { resolve(onRejected(reason)); } catch (error) { reject(error); } } }, ]); this._executeHandlers(); }); } /** * Promise catch method * @param {Function} onRejected - Error handler * @returns {SyncPromise} New promise */ catch(onRejected) { return this.then(null, onRejected); } /** * Promise finally method * @param {Function} onFinally - Finally handler * @returns {SyncPromise} New promise */ finally(onFinally) { return new SyncPromise((resolve, reject) => { let value; let isRejected = false; return this.then( (val) => { isRejected = false; value = val; if (onFinally) onFinally(); }, (reason) => { isRejected = true; value = reason; if (onFinally) onFinally(); }, ).then(() => { if (isRejected) { reject(value); } else { resolve(value); } }); }); } /** * Resolve the promise * @param {any} value - Resolution value * @private */ _resolve(value) { this._setResult(PromiseState.RESOLVED, value); } /** * Reject the promise * @param {any} reason - Rejection reason * @private */ _reject(reason) { this._setResult(PromiseState.REJECTED, reason); } /** * Set the final result of the promise * @param {number} state - Promise state * @param {any} value - Result value * @private */ _setResult(state, value) { if (this._state !== PromiseState.PENDING) { return; } // Handle thenable values if (this._isThenable(value)) { value.then(this._resolve, this._reject); return; } this._state = state; this._value = value; this._executeHandlers(); } /** * Execute pending handlers * @private */ _executeHandlers() { if (this._state === PromiseState.PENDING) { return; } const handlers = this._handlers.slice(); this._handlers = []; handlers.forEach((handler) => { if (handler[0]) { return; // Already executed } if (this._state === PromiseState.RESOLVED) { handler[1](this._value); } if (this._state === PromiseState.REJECTED) { handler[2](this._value); } handler[0] = true; // Mark as executed }); } /** * Check if value is thenable * @param {any} value - Value to check * @returns {boolean} True if thenable * @private */ _isThenable(value) { return Boolean(value && value.then && typeof value.then === "function"); } // Static methods /** * Create a resolved promise * @param {any} value - Resolution value * @returns {SyncPromise} Resolved promise */ static resolve(value) { return new SyncPromise((resolve) => { resolve(value); }); } /** * Create a rejected promise * @param {any} reason - Rejection reason * @returns {SyncPromise} Rejected promise */ static reject(reason) { return new SyncPromise((_, reject) => { reject(reason); }); } /** * Wait for all promises to resolve * @param {Array} promises - Array of promises * @returns {SyncPromise} Promise that resolves to array of results */ static all(promises) { return new SyncPromise((resolve, reject) => { if (promises.length === 0) { resolve([]); return; } const results = new Array(promises.length); let completedCount = 0; promises.forEach((promise, index) => { SyncPromise.resolve(promise).then( (value) => { results[index] = value; completedCount++; if (completedCount === promises.length) { resolve(results); } }, (reason) => { reject(reason); }, ); }); }); } /** * Wait for first promise to resolve * @param {Array} promises - Array of promises * @returns {SyncPromise} Promise that resolves to first result */ static race(promises) { return new SyncPromise((resolve, reject) => { promises.forEach((promise) => { SyncPromise.resolve(promise).then(resolve, reject); }); }); } /** * Wait for all promises to settle * @param {Array} promises - Array of promises * @returns {SyncPromise} Promise that resolves to array of results */ static allSettled(promises) { return new SyncPromise((resolve) => { if (promises.length === 0) { resolve([]); return; } const results = new Array(promises.length); let completedCount = 0; promises.forEach((promise, index) => { SyncPromise.resolve(promise).then( (value) => { results[index] = { status: "fulfilled", value }; completedCount++; if (completedCount === promises.length) { resolve(results); } }, (reason) => { results[index] = { status: "rejected", reason }; completedCount++; if (completedCount === promises.length) { resolve(results); } }, ); }); }); } } /** * Create a resolved sync promise * @param {any} value - Resolution value * @returns {SyncPromise} Resolved promise */ function resolvedSyncPromise(value) { return new SyncPromise((resolve) => { resolve(value); }); } /** * Create a rejected sync promise * @param {any} reason - Rejection reason * @returns {SyncPromise} Rejected promise */ function rejectedSyncPromise(reason) { return new SyncPromise((_, reject) => { reject(reason); }); } module.exports = { SyncPromise, resolvedSyncPromise, rejectedSyncPromise, PromiseState, };