最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 关于手写promise 的方法

    正文概述 掘金(Echo759)   2020-12-16   572

    本人最近在学习 promise 的相关内容与大家分享,若有不对的地方欢迎大家指正,一起学习进步 关于手写promise 的方法

    一、写一个同步的 promise

    1、new Promise((resolve,reject)=>{}) 传入的是一个 executor ,且参数传入后就同步执行
    2、executor 有两个参数,resolve/reject且都可以执行,所以都是函数

    function Promise (executor){  // 构造对象
        // 初始化参数
        this.status = 'pending';
        this.value = null;
        this.reason = null;
        // 定义 resolve 
        const resolve = value =>{
            if(this.status === 'pending'){
                this.status = 'rsolved';
                this.value = value;
            }
        }
        // 定义 reject 
        const reject = reason => {
            if(this.status === 'pending'){
                this.status = 'rejected';
                this.reason =reason;
            }
        }
        // 立即执行
        executor(resolve,reject);
    }
    
    // promise 的 then 方法
    Promise.prototype.then = function(onFulfilled,onRejected){
        if(this.status === 'resolved'){
            onFulfilled(this.value);
        }
        if(this.status === 'rejected'){
            onRejected(reason);
        }
    }
    
    
    

    掌握这些内容就可以初出江湖了
    关于手写promise 的方法

    二、解决异步调用问题

    1、当 executor 中存在 setTimeout 等方法时会产生异步调用,此时我们需要将onFulfilled()/onRejected(),放到一个数组中等 executor 中的内容出结果后再进行调用
    2、then 后定义的内容是异步执行的,需要对其中的内容使用process.nextTick() 方法进行处理

    function Promise (executor){
        this.status = 'pending';
        this.value = null;
        this.reason = null;
        // 添加数组当 executor 中异步时,保存函数
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
    
        const resolve = value =>{
            if(this.status === 'pending'){
                this.status = 'resolved';
                this.value = value;
                // 当 executor 出结果时调用函数
                this.onFulfilledCallbacks.map(callback=>{
                    callback(this.value);
                });
            }
        }
        const reject = reason => {
            if(this.status === 'pending'){
                this.status = 'rejected';
                this.reason =reason;
                // 当 executor 出结果时调用函数
                this.onRejectedCallbacks.map(callback=>{
                    callback(this.reason);
                });
            }
        }
        executor(resolve,reject);
    }
    Promise.prototype.then = function(onFulfilled,onRejected){
        // 添加 process.nextTick() 增加异步
        if(this.status === 'resolved'){
            process.nextTick(()=>{
                onFulfilled(this.value);
            })
        }
        if(this.status === 'rejected'){
            process.nextTick(()=>{
                onRejected(this.reason);
            })
        }
        // 在 status 是 pending 状态下向数组添加属性
        if(this.status === 'pending'){
            this.onFulfilledCallbacks.push(
                process.nextTick(()=>{
                    onFulfilled(this.value);
                })
            )
            this.onRejectedCallbacks.push(
                process.nextTick(()=>{
                    onRejected(this.reason);
                })
            )
        }
    }
    
    
    

    还没完,重头戏刚刚开始
    关于手写promise 的方法

    三、解决链式调用

    我们常用的 new Promise().then().then() 就是链式调用,常用来解决回调地狱
    链式调用中分三种情况

    1、then() 的参数中没有定义 onFulfilled/onRejected 时
    2、then() 的参数中,返回的不是一个 promise 或无返回值时
    3、then() 的参数中返回一个 promise

    对应这三种情况 then 返回的 promise (这里称之为 P2)也存在三种不同的状态,反别是

    1、将上一层的 promise 的 data 传给 P2
    2、将这非 promise 的内容作为 data 传给 P2
    3、将参数中返回的 promise 的 data 传给 P2

    所以现在要构建一个 P2 且要将上述的三种情况串在一起,根据它们的状态判断 P2 的状态

    上代码

    function Promise (executor){
        this.status = 'pending';
        this.value = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
    
        const resolve = value =>{
            if(this.status === 'pending'){
                this.status = 'resolved';
                this.value = value;
                this.onFulfilledCallbacks.map(callback=>{
                    callback(this.value);
                });
            }
        }
        const reject = reason => {
            if(this.status === 'pending'){
                this.status = 'rejected';
                this.reason =reason;
                this.onRejectedCallbacks.map(callback=>{
                    callback(this.reason);
                });
            }
        }
        executor(resolve,reject);
    }
    Promise.prototype.then = function(onFulfilled,onRejected){
        // case1: 如果未定义 onFulfilled/onRejected 自动初始化
        if(typeof onFulfilled !== 'function'){
            onFulfilled = value => value;
        }
        if(typeof onRejected !== 'function'){
            onRejected = err => {throw err;}
        }
        // case2:/case3: 定义了 onFulfilled/onRejected 
        // P2 的状态由 then 中的参数状态决定
        // 将 then 中的参数表达式命名为 P3
        // 所以(P3)then 中的参数表达式必须写在P2中(只有在P2中才能看到P2的 resolve/reject)
        let p2 = new Promise((resolve, reject)=>{
            if(this.status === 'resolved'){
                process.nextTick(()=>{
                    try {
                        let P3 = onFulfilled(this.value);
                        // 建立 P2 与 P3 的联系
                        resolvePromiseRelation(p2,P3,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                    
                })
            }
            if(this.status === 'rejected'){
                process.nextTick(()=>{
                    try {
                        let P3 = onRejected(this.reason);
                        // 建立 P2 与 P3 的联系
                        resolvePromiseRelation(p2,P3,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                    
                })
            }
            if(this.status === 'pending'){
                this.onFulfilledCallbacks.push(() =>{
                    process.nextTick(()=>{
                        try {
                            let P3 = onFulfilled(this.value);
                            // 建立 P2 与 P3 的联系
                            	resolvePromiseRelation(p2,P3,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                })
                this.onRejectedCallbacks.push(()=>{
                    process.nextTick(()=>{
                        try {
                            let P3 = onRejected(this.reason);
                            // 建立 P2 与 P3 的联系
                            resolvePromiseRelation(p2,P3,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                })
            }
        });
        return p2;
    }
    // 建立 P2 与 P3 的连接
    function resolvePromiseRelation(P2,P3,P2Resolve,P2Reject){
        // 如果 P2 === P3 会陷入死循环
        if(P2 === P3){
            return P2Reject(new TypeError('Dead cycle P2 = P3'));
        };
        let called = false;
        // 判断 P3 是个什么东西
        if(P3 !== null && (typeof P3 === 'function' || typeof P3 === 'object')){
            try {
                let then = P3.then;
                if(typeof then === 'function'){
                     // 说明 P3 是一个 promise 对象
                    then.call(P3, data => {
                        // 运行一次之后本次递归不能再来运行
                        if(called) return;
                         called = true;
                         // 递归保证 data 中不是一个 promise 对象
                         resolvePromiseRelation(P3,data,P2Resolve,P2Reject);
                    }, err => {
                        // 当出错后不再进行递归
                        if(called) return;
                         called = true;
                         P2Reject(err);
                    });
                }else{
                    // case2: 返回的不是 promise 对象
                    P2Resolve(P3);
                };
            } catch (e) {
                // 当出错后不再进行递归
                if(called) return;
                called = true;
                P2Reject(e);
            }
            
        }else{
            // case2: 返回的不是 promise 对象
            P2Resolve(P3);
        };
    }
    

    关于手写promise 的方法
    还没结束,继续ing...
    ...
    ...
    此时产生一个问题,若 resolve 的参数是一个 promise 对象时,程序状态不会根据此对象状态改变,会将这个 promise 对象内容返回,这不是我们希望看到的!
    此时我们需要对进入进入 resolve 的东西进行区分,若进入的是 promise 对象需要对其不断进行递归,直到进入的不再是 promise 对象

    代码更改后状态

    function Promise (executor){
        this.status = 'pending';
        this.value = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        // 由于 resolve 存在递归所以需要 called 监视状态
        this.called = false;
    
        const _resolve = value =>{
            this.status = 'resolved';
            this.value = value;
            this.onFulfilledCallbacks.map(callback=>{
                callback(this.value);
            });
        }
        const reject = reason => {
            if(this.status === 'pending'&& !this.called ){
                this.caiied = true;
                this.status = 'rejected';
                this.reason = reason;
                this.onRejectedCallbacks.map(callback=>{
                    callback(this.reason);
                });
            }
        }
        // resolve 给入的有可能是一个 promise 对象,若是 promise 需要进行处理
        const resolve = value =>{
            // 进入时检测 called 的状态
            if(this.status === 'pending' && !this.called ){
                this.caiied = true;
    
                // called 防止出错后递归不停止
                let called = false;
                if(value !== null && (typeof value === 'function' || typeof value === 'object')){
                    try {
                        let then = value.then;
                        if(typeof then === 'function'){
                            then.call(value, data => {
                                if(called) return;
                                called = true;
                                // 递归前恢复 this.called 的状态防止无法递归
                                this.called = false;
                                // data 还可能是 promise 对象,所以再进行递归
                                resolve(data);
                            },err => {
                                if(called) return;
                                called = true;
                                // 递归前恢复 this.called 的状态防止无法递归
                                this.called = false;
                                reject(err);
                            });
                        }else{
                            _resolve(value);
                        };
                    } catch(e) {
                        if(called) return;
                        called = true;
                        // 递归前恢复 this.called 的状态防止无法递归
                        this.called = false;
                        reject(e);
                    }
                }else{
                    _resolve(value);
                };
            }
        }
    
        executor(resolve,reject);
    }
    Promise.prototype.then = function(onFulfilled,onRejected){
        if(typeof onFulfilled !== 'function'){
            onFulfilled = value => value;
        }
        if(typeof onRejected !== 'function'){
            onRejected = err => {throw err;}
        }
        let p2 = new Promise((resolve, reject)=>{
            if(this.status === 'resolved'){
                process.nextTick(()=>{
                    try {
                        let P3 = onFulfilled(this.value);
                        resolvePromiseRelation(p2,P3,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }
            if(this.status === 'rejected'){
                process.nextTick(()=>{
                    try {
                        let P3 = onRejected(this.reason);
                        resolvePromiseRelation(p2,P3,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }
            if(this.status === 'pending'){
                this.onFulfilledCallbacks.push(() =>{
                    process.nextTick(()=>{
                        try {
                            let P3 = onFulfilled(this.value);
                            resolvePromiseRelation(p2,P3,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                })
                this.onRejectedCallbacks.push(()=>{
                    process.nextTick(()=>{
                        try {
                            let P3 = onRejected(this.reason);
                            resolvePromiseRelation(p2,P3,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                })
            }
        });
        return p2;
    }
    function resolvePromiseRelation(P2,P3,P2Resolve,P2Reject){
        if(P2 === P3){
            return P2Reject(new TypeError('Dead cycle P2 = P3'));
        };
        let called = false;
        if(P3 !== null && (typeof P3 === 'function' || typeof P3 === 'object')){
            try {
                let then = P3.then;
                if(typeof then === 'function'){
                    then.call(P3, data => {
                        if(called) return;
                         called = true;
                         resolvePromiseRelation(P3,data,P2Resolve,P2Reject);
                    }, err => {
                        if(called) return;
                         called = true;
                         P2Reject(err);
                    });
                }else{
                    P2Resolve(P3);
                };
            } catch (e) {
                if(called) return;
                called = true;
                P2Reject(e);
            }
        }else{
            P2Resolve(P3);
        };
    }
    

    终于 promise 代码写完了,紧接着就是 promise 的成员函数和方法....
    关于手写promise 的方法
    剩下的代码下次更新....


    起源地下载网 » 关于手写promise 的方法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元