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
| const isFunction = obj => typeof obj === 'function' , isObject = obj => !!(obj && typeof obj === 'object') , isThenable = obj => (isFunction(obj) || isObject(obj)) && 'then' in obj , isPromise = promise => promise instanceof Promise , nextTick = queueMicrotask || setTimeout
const PENDING = 'pending', FULFILLED = 'fulfilled', REJECTED = 'rejected'
class Promise { result = null state = PENDING callbacks = [] constructor(fn) { let onFulfilled = value => this.#transition(FULFILLED, value) let onRejected = reason => this.#transition(REJECTED, reason)
let ignore = false let resolve = value => ignore || (ignore = true, this.#resolvePromise(value, onFulfilled, onRejected)) let reject = reason => ignore || (ignore = true, onRejected(reason))
try { fn(resolve, reject) } catch (error) { reject(error) } }
then(onFulfilled, onRejected) { return new Promise((resolve, reject) => { let callback = { onFulfilled, onRejected, resolve, reject }
if (this.state === PENDING) this.callbacks.push(callback) else nextTick(() => handleCallback(callback, this.state, this.result)) }) }
#transition(state, result) { this.state = state, this.result = result nextTick(() => (this.callbacks.map(e => handleCallback(e, state, result)), this.callbacks.length = 0)) }
#resolvePromise(result, resolve, reject) { if (result === this) return reject(new TypeError('Can not fufill promise with itself'))
if (isPromise(result)) return result.then(resolve, reject)
if (isThenable(result)) { try { let then = result.then if (isFunction(then)) return new Promise(then.bind(result)).then(resolve, reject) } catch (error) { return reject(error) } }
resolve(result) } }
const handleCallback = (callback, state, result) => { let { onFulfilled, onRejected, resolve, reject } = callback try { if (state === FULFILLED) isFunction(onFulfilled) ? resolve(onFulfilled(result)) : resolve(result) if (state === REJECTED) isFunction(onRejected) ? resolve(onRejected(result)) : reject(result) } catch (error) { reject(error) } }
Promise.prototype.catch = function (onRejected) { return this.then(null, onRejected) }
Promise.resolve = value => new Promise(resolve => resolve(value)) Promise.reject = reason => new Promise((_, reject) => reject(reason))
const resolved = value => new Promise(resolve => resolve(value)) const rejected = reason => new Promise((_, reject) => reject(reason))
const deferred = () => { let promise, resolve, reject promise = new Promise(($resolve, $reject) => { resolve = $resolve reject = $reject }) return { promise, resolve, reject } }
module.exports = { resolved, rejected, deferred }
|