Promise这个构造函数与别的不一样,尽管平时使用时比较爽,但是站在函数设计者的角度来看就比较怪异。首先构造函数的参数是个函数(executor),这个函数的两个参数resolve与reject又是两个函数,且是在Promise构造函数内部定义的,调用executor时需要作为executor的参数。
Promise的then方法的参数又是两个函数(onFulfilled与onRejected),这两函数会在该promise实例resolve或者reject时分别调用,且then方法还可以链式调用与值穿透。看起来很像一堆函数在互相作用,但Promise的用法却是面向对象的方式,所以容易让人困惑。
先不考虑then方法的链式调用与值穿透,实现一个简易版的promise。
一个普通的不支持链式调用的promise
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
| function MyPromise(executor){ this.value = undefined this.reason = undefined this.status = 'pending' this.onResolvedCallbacks = [] this.onRejectedCallbacks = [] const self = this function resolve(value){ if (self.status === 'pending') { self.status = 'resolve'; self.value = value; self.onResolvedCallbacks.forEach(function (fn) { return fn(); }); } } function reject(reason){ if (self.status === 'pending') { self.status = 'reject'; self.reason = reason; self.onRejectedCallbacks.forEach(function (fn) { return fn(); }); } } executor(resolve,reject) } MyPromise.prototype.then = function (onFulfilled,onRejected){ if(this.status === 'resolve'){ onFulfilled(this.value) } if(this.status === 'reject'){ onRejected(this.reason) } if (this.status === 'pending') { this.onResolvedCallbacks.push( ()=> { onFulfilled(this.value); }); this.onRejectedCallbacks.push( ()=> { onRejected(this.reason); }); } }
|
用一个例子来试一下我们的MyPromise
1 2 3 4 5 6 7
| new MyPromise((resolve,reject)=>{ setTimeout(() => { resolve(1000) }, 1000) }).then(val=>{ console.log(val, 'done1') })
|
一切运行良好,但是这种实现不支持链式调用与promise值穿透,比如这样写就不行了。
1 2 3 4 5 6 7 8 9
| new MyPromise((resolve,reject)=>{ setTimeout(() => { resolve(1000) }, 1000) }).then(val=>{ console.log(val, 'done1') }).then(()=>{ console.log('done2') })
|
支持链式调用的promise
其实promise链式调用的实现很简单,给then方法默认返回一个promise即可。
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
| MyPromise.prototype.then = function (onFulfilled,onRejected){ return new MyPromise((resolve,reject)=>{ if(this.status === 'resolve'){ try{ const x = onFulfilled(this.value) if(x instanceof MyPromise){ x.then(resolve,reject) } else{ resolve(x) } } catch (e){ reject(e) } } if(this.status === 'reject'){ try{ const x = onRejected(this.value) if(x instanceof MyPromise){ x.then(resolve,reject) } else{ resolve(x) } } catch (e){ reject(e) } } if(this.status === 'pending'){ this.onResolvedCallbacks.push(()=>{ try{ const x = onFulfilled(this.value) if(x instanceof MyPromise){ x.then(resolve,reject) } else{ resolve(x) } } catch (e){ reject(e) } }) this.onRejectedCallbacks.push(()=>{ try{ const x = onRejected(this.reason) if(x instanceof MyPromise){ x.then(resolve,reject) } else{ resolve(x) } } catch (e){ reject(e) } }) } }) }
|