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