IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Promsie源码解析一步到位 -> 正文阅读

[JavaScript知识库]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的理解已经更加深入!看到这里请给我点个赞吧!原创不易,代码都是我敲到凌晨才出来的。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:50:47  更:2021-10-24 14:52:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/12 21:05:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码