手写 Promise
1.promise/A+规范规定
- promise 是一个拥有 then 方法的对象或函数,其行为符合本规范;
一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function MyPromise(executor) { var _this = this this.state = PENDING; //状态 this.value = undefined; //成功结果 this.reason = undefined; //失败原因 function resolve(value) {} function reject(reason) {} } MyPromise.prototype.then = function (onFulfilled, onRejected) { }; module.exports = MyPromise;
2.当我们实例化Promise时,构造函数会马上调用传入的执行函数executor。
因此在Promise中构造函数立马执行,同时将resolve函数和reject函数作为参数传入
但是executor也会可能存在异常,因此通过try/catch来捕获一下异常情况。
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function MyPromise(executor) { var _this = this this.state = PENDING; //状态 this.value = undefined; //成功结果 this.reason = undefined; //失败原因 function resolve(value) {} function reject(reason) {} try { executor(resolve, reject); } catch (e) { reject(e); } } MyPromise.prototype.then = function (onFulfilled, onRejected) { }; module.exports = MyPromise;
3.promise/A+规范中规定
- 当Promise对象已经由等待态(Pending)改变为执行态(Fulfilled)或者拒绝态(Rejected)后,就不能再次更改状态,且终值也不可改变。
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function MyPromise(executor) { var _this = this this.state = PENDING; //状态 this.value = undefined; //成功结果 this.reason = undefined; //失败原因 function resolve(value) { if(_this.state === PENDING){ _this.state = FULFILLED _this.value = value } } function reject(reason) { if(_this.state === PENDING){ _this.state = REJECTED _this.reason = reason } } try { executor(resolve, reject); } catch (e) { reject(e); } } MyPromise.prototype.then = function (onFulfilled, onRejected) { }; module.exports = MyPromise;
4.当Promise的状态改变之后,不管成功还是失败,都会触发then回调函数。因此,then的实现也很简单,就是根据状态的不同,来调用不同处理终值的函数。
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function MyPromise(executor) { var _this = this this.state = PENDING; //状态 this.value = undefined; //成功结果 this.reason = undefined; //失败原因 function resolve(value) { if(_this.state === PENDING){ _this.state = FULFILLED _this.value = value } } function reject(reason) { if(_this.state === PENDING){ _this.state = REJECTED _this.reason = reason } } try { executor(resolve, reject); } catch (e) { reject(e); } } MyPromise.prototype.then = function (onFulfilled, onRejected) { if(this.state === FULFILLED){ typeof onFulfilled === 'function' && onFulfilled(this.value) } if(this.state === REJECTED){ typeof onRejected === 'function' && onRejected(this.reason) } }; module.exports = MyPromise;
5.当then里面函数运行时,resolve由于是异步执行的,还没有来得及修改state,此时还是PENDING状态;因此我们需要对异步的情况做一下处理。
参考发布订阅模式,在执行then方法的时候,如果当前还是PENDING状态,就把回调函数寄存到一个数组中,当状态发生改变时,去数组中取出回调函数;
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function MyPromise(executor) { var _this = this this.state = PENDING; //状态 this.value = undefined; //成功结果 this.reason = undefined; //失败原因 this.onFulfilled = [];//成功的回调 this.onRejected = []; //失败的回调 function resolve(value) { if(_this.state === PENDING){ _this.state = FULFILLED _this.value = value _this.onFulfilled.forEach(fn => fn(value)) } } function reject(reason) { if(_this.state === PENDING){ _this.state = REJECTED _this.reason = reason _this.onRejected.forEach(fn => fn(reason)) } } try { executor(resolve, reject); } catch (e) { reject(e); } } MyPromise.prototype.then = function (onFulfilled, onRejected) { if(this.state === FULFILLED){ typeof onFulfilled === 'function' && onFulfilled(this.value) } if(this.state === REJECTED){ typeof onRejected === 'function' && onRejected(this.reason) } if(this.state === PENDING){ typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled) typeof onRejected === 'function' && this.onRejected.push(onRejected) } }; module.exports = MyPromise;
6. then的逻辑就开始复杂了
promise/A+规范
- then 方法必须返回一个 promise 对象
then的执行过程:
- 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:
[[Resolve]](promise2, x)
- 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
- 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
- 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因
第一点,我们知道onFulfilled和onRejected执行之后都会有一个返回值x,对返回值x处理就需要用到Promise解决过程;
第二点,需要对onFulfilled和onRejected进行异常处理,没什么好说的;
第三和第四点,说的其实是一个问题,如果onFulfilled和onRejected两个参数没有传,则继续往下传(值的传递特性)
/** * Promise 解决过程 * 是对新的promise2和上一个执行结果 x 的处理,规范中定义的第一点 * 操作说明: 1.x 与 promise 相等 1.如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise 2.x 为 Promise 1.如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝 2.如果 x 处于执行态,用相同的值执行 promise 3.如果 x 处于拒绝态,用相同的据因拒绝 promise 3.x 为对象或函数 1.把 x.then 赋值给 then 2.如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise 3.如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise: 1.如果 resolvePromise 以值 y 为参数被调用,则运行 [Resolve] 2.如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise 3.如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 4.如果 then 不是函数,以 x 为参数执行 promise 4.如果 x 不为对象或者函数,以 x 为参数执行 promise * @param promise2 新的Promise对象 * @param x 上一个then的返回值 * @param resolve promise2的resolve * @param reject promise2的reject */ function resolvePromise(promise2, x, resolve, reject) { } MyPromise.prototype.then = function (onFulfilled, onRejected) { var _this = this onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } var promise2 = new Promise((resolve, reject)=>{ if(_this.state === FULFILLED){ setTimeout(()=>{ try { let x = onFulfilled(_this.value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } else if(_this.state === REJECTED){ setTimeout(()=>{ try { let x = onRejected(_this.reason) resolvePromise(promise2, x ,resolve, reject) } catch (error) { reject(error) } }) } else if(_this.state === PENDING){ _this.onFulfilled.push(()=>{ setTimeout(()=>{ try { let x = onFulfilled(_this.value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) }) _this.onRejected.push(()=>{ setTimeout(()=>{ try { let x = onRejected(_this.reason) resolvePromise(promise2, x ,resolve, reject) } catch (error) { reject(error) } }) }) } }) return promise2 };
定义好函数后,根据规范写出实现
function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { reject(new TypeError('Chaining cycle')); } if (x !== null && (typeof x === 'object' || typeof x === 'function')) { //函数或对象 // 只执行一次resolve/reject let used; // 取then的时候也需要try/catch try { let then = x.then // 取出then后,回到3.3,判断如果是一个函数,就将 x 作为函数的作用域 this 调用,同时传入两个回调函数作为参数。 if(typeof then === 'function'){ then.call(x, (y)=>{ if (used) return; used = true resolvePromise(promise2, y, resolve, reject) }, (r) =>{ if (used) return; used = true reject(r) }) } else { if (used) return; used = true resolve(x) } } catch(e){ if (used) return; used = true reject(e) } } else { //普通值 resolve(x) } }