Promsie源码解析一步到位

碎碎念:

亲爱的读者:你好!我叫 Changlon —— 一个非科班程序员、一个致力于前端的开发者、一个热爱生活且又时有忧郁的思考者。

如果我的文章能给你带来一些收获,你的点赞收藏将是对我莫大的鼓励!

我的邮箱:thinker_changlon@163.com

我的Github: https://github.com/Changlon

本章我将带领大家手写一个符合promise/a+ 规范的Promise。可以说这是前端工程师必须要掌握的一个技术,在项目中使用到的非常多。
那么promsie究竟是如何实现的呢?本篇文章将通过手写一个promsie来揭开Promsie神秘的面纱!
下面请拿起你的键盘跟我一起来撸一个promise吧!相信写完之后你会对Promise有更加深刻的理解!

在开始前我想请大家先阅读一下什么是promsie/a+规范,它规定了我们如何去实现这个类。

相关链接
promise/a+规范网址
myPromise源码github地址

一 、promsie构造函数

先来写一个promise的构造函数吧,先来想一想我们平时使用Promise都是一般这样使用的 new Promise((resolve,reject)=>{}) 。我们要传一个执行函数作为构造器的参数。这个执行函数是在实例化类的时候执行的,也就是说这里面的代码是非异步执行。

/** promsie构造函数 */
export default class promise{ 
    constructor(hanlder) { 
        this.checkHandler(hanlder) ?  
            this.init(hanlder)
        : void 0
    }
    
    /**初始化promise */
    init(hanlder) {  
    }
    /**检查构造器参数 */
    checkHandler(hanlder) {  
        if(!hanlder) throw new Error('new promsie 需要一个函数类型的参数!') 
        if(!(hanlder instanceof Function)) throw new Error('new promsie 需要一个函数类型的参数!') 
        return true 
    }

}

上面的代码我们先判断在new promise类时是否传入了正确的参数,如果检查参数符合要求则进入init方法初始化类,不符合要求则抛出我们规定的异常。
接下来我们就来考虑如何去实现这个init 方法。首先我们需要记录一下实例对象,然后在实例上定义一组状态变量用来确定当前promise的状态。然后去执行这个执行函数handler就可以了。

		//记录原本的实例对象
		const that = this 
		//定义状态变量
        that.pending = "pending"
        that.fulfilled = "fulfilled"
        that.rejected = 'rejected' 
        that.status = this.pending   
        //定义value fulfilled或rejected状态返回的值
        that.value = undefined  
        

        /** fulfilled状态处理函数 */
        function onResolved(value) {
        	//如果状态一改变就不能改变当前状态了
            if(that.status!=that.pending) return void 0 
            that.status = that.fulfilled  
            that.value = value 
        }

        /** rejected状态处理函数 */
        function onRejected(reason) { 
            if(that.status!=that.pending) return void 0 
            that.status = that.rejected  
            that.value = reason
        }
        
        //使用try...catch 捕获用户代码可能出现的异常
        try {
            hanlder(onResolved,onRejected) 
        }catch(e)  {
            throw new Error(`用户自定义程序报错:${e}`)
        }

二 、then函数

我们再来回顾一下Promise的用法。当我们在执行函数中同步resolve,reject值时,then函数也是同步执行的。如何resolve,reject值是在异步代码中,那么then函数会在异步代码执行后再去执行。
举个例子:

//测试例子 demo1
const p = new promise((resolve,reject)=>{  
    // resolve('test')  //这里的 'test'会立刻打印
	  setTimeout(()=>{ 
            resolve('test')
      },1000)
})

//这时候 'test' 会在1s后才能打印出来
p.then(value=>{
    console.log(value)
},reason=>{
    console.log(reason)
})

我们发现then函数是根据 status状态来异步或同步执行的 。当状态是 'fulfilled''rejected'时候then函数同步执行,如果是'pending'状态则说明改变状态的函数是在下一个事件循环中才被执行,我们这时候也需要将对then中处理结果值得函数onFulfilled,onRejected放到异步队列中去执行。
then函数的简单实现如下:

 then(onFulfilled,onRejected) {   
        const that = this 
        const value = this.value 
     	switch (that.status) { 
                    case 'pending': 
                        setTimeout(()=>{
                            that.then(onFulfilled,onRejected) 
                        break 
                    case 'fulfilled': 
                            onFulfilled(value) 
                        break 
                    case 'rejected' :
                            onRejected(value)
                        break 
                        
                }
    }

三、 实现promise/a+规范的then函数

上面实现的then函数也仅仅能满足我们上面测试用例demo1的情况,要实现一个符合promise/a+规范的then函数我们还需要实现以下要求:

摘录自promise/a+网站
then must return a promise [3.3].
promise2 = promise1.then(onFulfilled, onRejected);
If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

总结一下就是:
1.then函数返回一个promise
2.在onFulfilled or onRejected中返回一个值如果这个值是非promise类型的则直接返回 'fulfilled'状态的promise对象,如果是promise类型的对象则直接返回这个对象。
3.如果在onFulfilled or onRejected用户给出的执行函数中出现报错则必须返回一个'rejected'状态的promise
4. 如果在一个then函数中 onFulfilled未给出,并且状态已经为'fulfilled'我们需要将状态值 value 作为返回的promise的状态值。onRejected未给出也同样如此。

下面我们来分析如何实现上面的要求。第一点很好实现我们直接修改then函数

then(onFulfilled,onRejected) {   
        const that = this 
        const value = this.value 
        return new promise((resolve,reject)=>{
			switch (that.status) { 
	                    case 'pending': 
	                        setTimeout(()=>{
	                            that.then(onFulfilled,onRejected) 
	                        break 
	                    case 'fulfilled': 
	                            onFulfilled(value) 
	                        break 
	                    case 'rejected' :
	                            onRejected(value)
	                        break 
	                        
	                }
		})
     	
    }

可这样是不行的,返回的是一个状态永远为'pending'promise,我们需要记录onFulfilled,onRejected的返回值然后将返回值resolve
如下修改switch中的代码

   case 'fulfilled': 
		 resolve(onFulfilled(value))
		break 
	case 'rejected' :
 		resolve(onRejected(value)) 
		break 

可这样还是不行,如果返回的是一个promise对象不是js基本数据类型怎么办?还有 onFulfilledonRejected 是使用者给出的函数,如果未传入或者在执行过程中报异常了怎么处理?
针对上面的问题我们逐一分析。
1.如果onFulfilled,onRejected返回的是一个promise我们怎么办,我们定义一个遍历函数去遍历这个promise状态直到最后的状态值是基本数据类型的时候我们再在返回的promise中去resolve,或reject这个值。
2.onFulfilledonRejected 未传入怎么办? 如果未传入我们直接将它作为返回
promise状态值去向下传递。
3.onFulfilledonRejected 在执行过程中报异常怎么办? 我们直接将所有执行的代码包含在try...catch中一旦报错则返回'rejected'状态的promise即可。

根据上面的分析我们最终修改代码如下:

  then(onFulfilled,onRejected) {   
        const that = this 
        const value = this.value 
        return new promise((resolve,reject)=>{ 
            try {
                switch (that.status) { 
                    case 'pending': 
                        setTimeout(()=>{
                           const p =  that.then(onFulfilled,onRejected) 
                           p.then(value=>{resolve(value)},reason=>{reject(reason)})
                        })
                        break 
                    case 'fulfilled': 
                            onFulfilled? 
                            //  resolve(onFulfilled(value))  
                            void (()=>{
                                const p = onFulfilled(value) 
                                if(!(p instanceof promise)) return resolve(p)  
                                that.traversePromise(p,resolve,reject)
                            })()
                            : resolve(value)
                            // onFulfilled(value) 
                        break 
                    case 'rejected' :
                            onRejected ?  
                                // resolve(onRejected(value)) 
                            void (()=>{
                                const p = onRejected(value) 
                                if(!(p instanceof promise)) return resolve(p)  
                                that.traversePromise(p,resolve,reject)
                            })()
                            : reject(value) 
                            //onRejected(value)
                        break 
                        
                }
            }catch(e) {
                reject(e) 
            }
          
        })
        
    }

四 、实现catch捕获异常函数

	//catch的思路是捕获上一个then函数中出现的异常,返回的是一个promise
  catch(onRejected) {
        return this.then(void 0,onRejected) 
  }

五 、实现 resolve,reject静态函数

	
	//返回一个 'rejected'状态的promise
    static reject(p) { 
        return (p instanceof promise) ? p : new promise((r,j)=>{
            j(p)
        })
    }
    
 	 //返回一个 'resolved'状态的promise
    static resolve(p) {
        return (p instanceof promise) ? p : new promise((r,j)=>{
            r(p)
        })
    }

六、 实现 race,all函数

  /** 谁最快就先处理谁 */
    static race(promsies) { 
        if(!promsies) throw new Error('缺少promises参数!')   
        return new promise((resolve,reject)=>{
            for(let p of promsies) {
                promise.resolve(p)
                .then(value=>{
                    resolve(value)
                })
                .catch(err=>{
                    reject(err)
                })
            }
        })

    }


    /** 处理全部的promise,顺利状态按顺序返回结果,有错误状态返回第一个错误,但后面的promise也是执行的 */
    static all(promsies) {  
        if(!promsies) throw new Error('缺少promises参数!')   
        return new promise((resolve,reject)=>{
            const resolves = [] 
            let counter = 0 
            for(let i = 0 ;i<promsies.length;++i) {   
                const p = promsies[i]
                promise.resolve(p)
                .then(value=>{
                    resolves[i] = value 
                    counter++
                    counter === promsies.length ?  resolve(resolves) : void 0  
                },reason=>{
                     reject(reason)
                })
                
            }
        })
     
    }

以上就实现了一款比较简单的promise的版本,相信通过这些代码的练习你对promise的理解已经更加深入!看到这里请给我点个赞吧!原创不易,代码都是我敲到凌晨才出来的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智者_若愚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值