whynotgonow 2020-05-16
const PENDING = ‘pending‘ const FULFILLED = ‘fulfilled‘ const REJECTED = ‘rejected‘ function MyPromise(executor) { let self = this self.value = null self.error = null self.status = PENDING // 异步 readFile 尚未 resolve 的时候先存储所有成功回调。 // 即 thenable 方法中 status = PENDING 的时候先存储。 // 待异步 readFile 执行到 resolve 时,status 改变然后依次执行 onFulfilledCallbacks 中的回调函数。 self.onFulfilledCallbacks = [] self.onRejectedCallbacks = [] const resolve = (value) => { if (self.status !== PENDING) return; // res 或 rej 只走一条路径 setTimeout(() => { self.status = FULFILLED self.value = value self.onFulfilledCallbacks.forEach((callback) => callback(self.value)) // 异步逻辑执行回调 }) } const reject = (error) => { if (self.status !== PENDING) return; // res 或 rej 只走一条路径 setTimeout(() => { self.status = REJECTED self.error = error self.onRejectedCallbacks.forEach((callback) => callback(self.error)) // promise异步任务 }) } executor(resolve, reject) } // then 函数整体是一个同步进行的状态,遇到异步任务时,只有 this.status = PENDING MyPromise.prototype.then = function (onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === ‘function‘ ? onFulfilled : value => value onRejected = typeof onRejected === ‘function‘ ? onRejected : error => { throw error } let bridgePromise; let self = this; // PENDING 时同步存储进回调数组 callbacks // 异步 readFile 时走 PENDING,因为同步执行到 then 时,readFile 尚未 resolve if (self.status === PENDING) { // return promise 可以放在 if else 的最层 return bridgePromise = new MyPromise((resolve, reject) => { // new promise 立即执行 self.onFulfilledCallbacks.push((value) => { try { let x = onFulfilled(value) // 拿到 then 中回调返回的结果? resolvePromise(bridgePromise, x, resolve, reject); // x 可能还是 promise } catch (e) { reject(e) } }) self.onRejectedCallbacks.push((error) => { try { let x = onRejected(error); // 假若 x 还是一个 promise,不能直接 resolve resolve(x); } catch (e) { reject(e); } }); }) } else if (this.status === FULFILLED) { // 同步执行走到 FULFILLED return bridgePromise = new MyPromise((resolve, reject) => { try { let x = onFulfilled(self.value) resolvePromise(bridgePromise, x, resolve, reject) } catch (e) { reject(e) } }) } else { return bridgePromise = new MyPromise((resolve, reject) => { try { let x = onRejected(self.error) resolvePromise(bridgePromise, x, resolve, reject) } catch (e) { reject(e) } }) } } MyPromise.prototype.catch = function (onRejected) { return this.then(null, onRejected) } // finally 本质上是一个 then 方法 // 入参 callback 是一个函数,需要在 then 中执行 // 使用 Promise.resolve 会等 callback() 函数执行完后再返回结果,并将上一个 then 的 value 返回 MyPromise.prototype.finally = function (callback) { // this 即上一个 promise return this.then(value => { return MyPromise.resolve(callback()).then(() => value) }, error => { return MyPromise.resolve(callback()).then(() => { throw error; }) }) } MyPromise.resolve = function (callback) { // MyPromise.resolve 的职责就是返回一个 promise 对象,显然已经达到,故直接返回 if (callback instanceof MyPromise) return callback; return new MyPromise((resolve, reject) => { if (callback.then && typeof callback.then === ‘function‘) { callback.then(resolve, reject) } else { resolve(callback) } }) } MyPromise.reject = function (reason) { return new MyPromise((resolve, reject) => { reject(reason) }) } MyPromise.all = function (promises) { return new MyPromise((resolve, reject) => { let len = promises.length let result = [] let index = 0 if (len === 0) return resolve(resutl); for (let i = 0; i < len; i++) { // 统一转成 promise 对象处理 MyPromise.resolve(promises[i]).then(res => { result[i] = res index++; if (index === len) resolve(result); }).catch(err => { reject(err); }) } }) } MyPromise.race = function (promises) { return new MyPromise((resolve, reject) => { let len = promises.length if (len === 0) return; for (let i = 0; i < len; i++) { MyPromise.resolve(promises[i]).then(data => { resolve(data) return; }).catch(err => { reject(err) return; }) } }) } function resolvePromise(bridgePromise, x, resolve, reject) { if (x instanceof MyPromise) { if (x.status === PENDING) { x.then(y => { resolvePromise(bridgePromise, y, resolve, reject) }, error => { reject(error) }) } else { x.then(resolve, reject) } } else { resolve(x) } } let fs = require(‘fs‘) let readFilePromise = (filename) => { return new MyPromise((resolve, reject) => { fs.readFile(filename, (err, data) => { if (!err) { resolve(data) } else { reject(err) } }) }) } readFilePromise(‘./p6.html‘).then(data => { console.log(‘1_p6.html‘) return readFilePromise(‘./p6.html‘) }).then(data => { console.log(‘2_p6.html‘) })