JavaScript
参考工业聚:100 行代码实现 Promises/A+ 规范
1const isFunction = obj => typeof obj === 'function'2const isObject = obj => !!(obj && typeof obj === 'object') // null 的情况3const isThenable = obj => (isFunction(obj) || isObject(obj)) && 'then' in obj && isFunction(obj.then)4const isPromise = promise => promise instanceof Promise56const PENDING = 'pending'7const FULFILLED = 'fulfilled'8const REJECTED = 'rejected'910class Promise {11 constructor(fn) {12 this.status = PENDING13 this.value = undefined14 this.reason = undefined15 this.onFulfilledCallbacks = []16 this.onRejectedCallbacks = []17 function resolve(value) {18 if (this.status !== PENDING)19 return20 setTimeout(() => {21 this.status = FULFILLED22 this.value = value23 this.onFulfilledCallbacks.forEach(cb => cb(this.value))24 }, 0)25 }26 function reject(reason) {27 if (this.status !== PENDING)28 return29 setTimeout(() => {30 this.status = REJECTED31 this.reason = reason32 this.onRejectedCallbacks.forEach(cb => cb(this.reason))33 })34 }35 try {36 fn(resolve, reject)37 } catch (e) {38 reject(e)39 }40 }4142 then(onFulfilled, onRejected) {43 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value44 onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }45 return bridgePromise = new Promise((resolve, reject) => {46 if (this.status === FULFILLED) {47 setTimeout(() => {48 try {49 let result = onFulfilled(this.value)50 resolvePromise(bridgePromise, result, resolve, reject)51 } catch (e) {52 reject(e)53 }54 }, 0)55 } else if (this.status === REJECTED) {56 setTimeout(() => {57 try {58 let result = onRejected(this.reason)59 resolvePromise(bridgePromise, result, resolve, reject)60 } catch (e) {61 reject(e)62 }63 }, 0)64 } else if (this.status === PENDING) {65 this.onFulfilledCallbacks.push(() => {66 try {67 let result = onFulfilled(this.value)68 resolvePromise(bridgePromise, result, resolve, reject)69 } catch (e) {70 reject(e)71 }72 })73 this.onRejectedCallbacks.push(() => {74 try {75 let result = onRejected(this.reason)76 resolvePromise(bridgePromise, result, resolve, reject)77 } catch (e) {78 reject(e)79 }80 })81 }82 })83 }8485 catch(onRejected) {86 return this.then(null, onRejected)87 }8889 static resolve(p) {90 if (isPromise(p)) return p91 return new Promise((resolve, reject) => {92 if (isThenable(p)) p.then(resolve, reject)93 else resolve(p)94 })95 }9697 static reject(p) {98 return new Promise((_, reject) => reject(p))99 }100101 static all(promises) {102 return new Promise((resolve, reject) => {103 let values = []104 let count = 0105 function handle(value, index) {106 values[index] = value107 if (++count === promises.length) resolve(values)108 }109 // p 可能不是 Promise,所以用 Promise.resolve 包一下110 promises.forEach((p, i) => Promise.resolve(p).then(value => handle(value, i), reject))111 })112 }113114 static race(promises) {115 return new Promise((resolve, reject) => {116 promises.forEach(p => Promise.resolve(p).then(resolve, reject))117 })118 }119120 static allSettled(promises) {121 return new Promise((resolve) => {122 let results = []123 let count = 0124 function handle(result, index) {125 results[index] = result126 if (++count === promises.length) resolve(results)127 }128 promises.forEach((p, i) => Promise.resolve(p).then(129 value => handle({ status: 'fulfilled', value }, i),130 reason => handle({ status: 'rejected', reason }, i),131 ))132 })133 }134}135136function resolvePromise(bridgePromise, result, resolve, reject) {137 if (bridgePromise === result) {138 return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))139 }140 if (isPromise(result)) {141 if (result.status === PENDING) {142 result.then(y => resolvePromise(bridgePromise, y, resolve, reject), reject)143 } else {144 result.then(resolve, reject)145 }146 } else if (isThenable(result)) {147 result.then(y => resolvePromise(bridgePromise, y, resolve, reject), reject)148 } else {149 resolve(result)150 }151}