Open qiuhongbingo opened 4 years ago
function Promise(executor) { this.status = 'pending' // pending -> fulfilled 或者 pending -> rejected 一次性变化,不可逆转 this.value = null // resolve 的值 this.reason = null // reject 的值 // 针对 call 4,需要保存 then/catch 的方法数组,兼容多个 then/catch this.onFulfilledArray = [] this.onRejectedArray = [] const resolve = value => { // 兼容 then 的链式调用 if (value instanceof Promise) return value.then(resolve, reject) // 针对 call 2,利用 setTimeout 推入队列(宏任务),不阻塞主线程执行 setTimeout(() => { if (this.status === 'pending') { this.value = value this.status = 'fulfilled' this.onFulfilledArray.forEach(func => func(value)) } }) } const reject = reason => { setTimeout(() => { if (this.status === 'pending') { this.reason = reason this.status = 'rejected' this.onRejectedArray.forEach(func => func(reason)) } }) } // 如果出错,将会自动触发 rejected try { executor(resolve, reject) } catch (e) { reject(e) } } const resolvePromise = (promise2, result, resolve, reject) => { // 当 result 和 promise2 相等时,也就是说 onfulfilled 返回 promise2 时,进行 reject // 针对 call 6 的死循环处理方案 if (result === promise2) reject(new TypeError('error due to circular reference')) // 是否已经执行过 onfulfilled 或者 onrejected let consumed = false let thenable if (result instanceof Promise) { if (result.status === 'pending') { result.then(data => resolvePromise(promise2, data, resolve, reject), reject) } else { result.then(resolve, reject) } return } // 判断返回结果是否普通值 let isComplexResult = target => (typeof target === 'function' || typeof target === 'object') && target !== null // 如果返回的是疑似 Promise 类型 if (isComplexResult(result)) { try { thenable = result.then // 如果返回的是 Promise 类型,具有 then 方法 if (typeof thenable === 'function') { thenable.call( result, data => { if (consumed) return consumed = true // 针对 call 7 的 Promise 多级链式调用,这里用上递归 return resolvePromise(promise2, data, resolve, reject) }, error => { if (consumed) return consumed = true return reject(error) } ) } else { resolve(result) } } catch (e) { if (consumed) { return } consumed = true return reject(e) } } else { // 普通值直接返回 resolve(result) } } // then 之所以挂载在原型上,是基于性能考虑,避免重复实例多次 Promise.prototype.then = function(onfulfilled, onrejected) { // 针对 call 8,兼容 .then(null) 也不影响链式调用,从而实现穿透 onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data => { return data } onrejected = typeof onrejected === 'function' ? onrejected : error => { throw error } let promise2 if (this.status === 'fulfilled') { return (promise2 = new Promise((resolve, reject) => { setTimeout(() => { try { // 这个新的 promse2 resolved 的值为 onfulfilled 的执行结果 let result = onfulfilled(this.value) resolvePromise(promise2, result, resolve, reject) } catch (e) { reject(e) } }) })) } if (this.status === 'rejected') { return (promise2 = new Promise((resolve, reject) => { setTimeout(() => { try { // 这个新的 promise2 reject 的值为 onrejected 的执行结果 let result = onrejected(this.value) resolvePromise(promise2, result, resolve, reject) } catch (e) { reject(e) } }) })) } if (this.status === 'pending') { return (promise2 = new Promise((resolve, reject) => { this.onFulfilledArray.push(() => { try { let result = onfulfilled(this.value) resolvePromise(promise2, result, resolve, reject) } catch (e) { reject(e) } }) this.onRejectedArray.push(() => { try { let result = onrejected(this.reason) resolvePromise(promise2, result, resolve, reject) } catch (e) { reject(e) } }) })) } } Promise.prototype.catch = function(catchFunc) { // 利用 then 的第二个参数进行异常捕获 return this.then(null, catchFunc) } // 针对 call 10 Promise.resolve = function(value) { return new Promise((resolve, reject) => { resolve(value) }) } Promise.reject = function(value) { return new Promise((resolve, reject) => { reject(value) }) } // 针对 call 11 Promise.all = function(promiseArray) { if (!Array.isArray(promiseArray)) throw new TypeError('The arguments should be an array!') return new Promise((resolve, reject) => { try { let resultArray = [] const length = promiseArray.length for (let i = 0; i < length; i++) { promiseArray[i].then(data => { resultArray.push(data) if (resultArray.length === length) resolve(resultArray) }, reject) } } catch (e) { reject(e) } }) } // 针对 call 12 Promise.race = function(promiseArray) { if (!Array.isArray(promiseArray)) throw new TypeError('The arguments should be an array!') return new Promise((resolve, reject) => { try { const length = promiseArray.length for (let i = 0; i < length; i++) promiseArray[i].then(resolve, reject) // 谁快谁 resolve } catch (e) { reject(e) } }) } // call 1 // const promise = new Promise((resolve, reject) => { // resolve('data') // reject('error') // }) // promise.then( // data => { // console.log(data) // 会执行 // }, // error => { // console.log(error) // 不会执行 // } // ) // call 2 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('data') // }, 2000) // }) // promise.then(data => { // console.log(data) // 2s 后输出 data // }) // call 3 // const promise = new Promise((resolve, reject) => { // resolve('data') // }) // promise.then(data => { // console.log(data) // 后执行 // }) // console.log(1) // 先执行 // call 4 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('data') // }, 2000) // }) // promise.then(data => { // console.log(`1: ${data}`) // 2s 后输出 1: data // }) // promise.then(data => { // console.log(`2: ${data}`) // 2s 后输出 2: data // }) // call 5 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo') // }, 2000) // }) // promise // .then(data => { // console.log(data) // 2s 后输出 bingo // return `${data} next then` // }) // .then(data => { // console.log(data) // 紧接输出 bingo next then // }) // call 6 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo') // }, 2000) // }) // promise // .then( // (onfulfilled = data => { // console.log(data) // return onfulfilled(data) // 模拟死循环 // }) // ) // .then(data => { // console.log(data) // }) // call 7 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo') // }, 2000) // }) // promise // .then(data => { // console.log(data) // return new Promise((resolve, reject) => { // setTimeout(() => { // resolve(`${data} next then`) // }, 4000) // }).then(data => { // return new Promise((resolve, reject) => { // setTimeout(() => { // resolve(`${data} next then`) // }, 4000) // }) // }) // }) // .then(data => { // console.log(data) // }) // call 8 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo') // }, 2000) // }) // promise.then(null).then(data => { // 穿透实现 // console.log(data) // }) // call 9 // const promise = new Promise((resolve, reject) => { // setTimeout(() => { // reject('bingo error') // }, 2000) // }) // promise // .then(data => { // console.log(data) // }) // .catch(error => { // console.log(error) // 2s 后输出 bingo error // }) // call 10 // Promise.resolve('data').then(data => { // console.log(data) // 再输出 data // }) // console.log(1) // 先输出 1 // call 11 // const promise1 = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo 1') // }, 2000) // }) // const promise2 = new Promise((resolve, reject) => { // setTimeout(() => { // resolve('bingo 2') // }, 2000) // }) // Promise.all([promise1, promise2]).then(data => { // console.log(data) // 2s 后输出 ['bingo 1', 'bingo 2'] // }) // call 12 const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('bingo 1') }, 2000) }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('bingo 2') }, 4000) }) Promise.race([promise1, promise2]).then(data => { console.log(data) // 2s 后输出 bingo 1 })