美文网首页
不积跬步之手写Promise源码(下)

不积跬步之手写Promise源码(下)

作者: 雨飞飞雨 | 来源:发表于2022-03-11 20:15 被阅读0次
    promise.jpeg

    书接上回

    12 catch 方法与异常穿透的实现

    这个小节我们实现三个小细节:

    1. catch方法的实现
    2. 异常穿透
    3. 值传递

    catch方法的实现

    它的作用是捕获处理之前的错误.实现方式也非常简单

    //添加catch方法
    PromiseA.prototype.catch = function (onRejected){
        return this.then(undefined,onRejected)
    }
    

    我们只需要调用then方法就可以了,因为catch方法不需要成功的处理,只处理失败,所以我们传入失败的回调就可以了.

    异常穿透

    什么是异常穿透呢? 看一下官方的例子:

    let p = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            reject("error");
        },100)
    });
    const result = p.then(value=>{
       console.log(111)
    }).then(value=>{
        console.log(222)
    }).then(value=>{
        console.log(333)
    }).catch(reason=>{
        console.log(reason);
    })
    //error
    

    可以看到报的错误error已经到达了catch的回调函数中.而一旦换成我们自己的调用,就会报一下的错误:

    TypeError: type is not a function
        at callback (<anonymous>:65:30)
        at Object.onRejected (<anonymous>:101:21)
    

    在调用

    onRejected:function (){
        callback(onRejected);
    }
    

    的时候发生错误 ?表示type is not a function 也就是onRejected这个回调函数没有造成的.所以我们需要给它加上一个默认的:

    //添加 then 方法
    PromiseA.prototype.then = function (onResolved,onRejected){
        const self = this;
        
        //判断回调函数参数
        if(typeof onRejected !== 'function'){
            onRejected = reason => {
                throw reason
            }
        }
        //.....
    

    添加上该方法以后,一旦发现有错误,它的处理就是向后抛,一知道最后.

    测试用例:

    let p = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
            reject("error");
        },100)
    });
    const result = p.then(value=>{
       console.log(111)
    }).then(value=>{
        console.log(222)
    }).then(value=>{
        console.log(333)
    }).catch(reason=>{
        console.log(reason);
    })
    //error
    

    或者中间抛出错误:

    let p = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
           resolve("ok");
        },100)
    });
    const result = p.then(value=>{
        console.log(111)
    }).then(value=>{
        throw "error"
    }).then(value=>{
        console.log(333)
    }).catch(reason=>{
        console.log(reason);
    })
    //输出
    //111
    //error
    

    值传递

    实际上要达到的效果是 then方法中不写回调函数也可以传递到后面,
    所以和上面的类似,我们添加一个默认的方法就可以了.

    //添加 then 方法
    PromiseA.prototype.then = function (onResolved,onRejected){
        const self = this;
        
        //判断回调函数参数
        if(typeof onRejected !== 'function'){
            onRejected = reason => {
                throw reason
            }
        }
        //--------------修改代码的地方----------
         if(typeof onResolved !== "function"){
            onResolved = value => value;
        }
        //--------------修改代码的地方----------
        //...
    

    测试用例:

    let p = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
           resolve("ok");
        },100)
    });
    const result = p.then().then(value=>{
        console.log(value)
    })
    //输出
    ok
    

    可以看到我们中间的then方法虽然没有设置回调函数,但是还是把值传递到后面去了.

    13.Promise.resolve 的封装

    这个方法的特性在之前的小记中有记录,它返回一个Promise对象.

    而这个Promise对象的状态取决于传递给它的参数.看到这里是不是感觉耳熟,是的,和上面的情况一样.

    1. 返回非Promise对象的,比如123,ok,不返回就是undefined,那么它默认会执行返回成功的Promise对象,
    2. 返回Promise对象的,则由这个对象决定状态,如果这个这个对象是成功的,那么外部result就是成功,如果失败的,那么外部就是失败的.
    3. 如果抛出错误,那么外部对象就是失败的.

    所以我们可以这样实现:

    PromiseA.resolve = function (value){
        //返回Promise
        return new PromiseA((resolve,reject)=>{
            try{
                if(value instanceof PromiseA){
                    value.then(v=>{
                        resolve(v);
                    },r=>{
                        reject(r);
                    })
                }else{
                    resolve(value);
                }
            }catch (e){
                reject(e);
            }
        })
    }
    

    测试用例:

    let p = PromiseA.resolve( new PromiseA((resolve,reject)=>{
         reject("error");
    }));
    let p1 = PromiseA.resolve(new PromiseA((resolve,reject)=>{
        resolve("OK");
    }))
    let p2 = PromiseA.resolve(111);
     p.catch(e=>console.log(e))
     console.log(p)
     console.log(p1)
     console.log(p2)
     //输出结果
     error
    PromiseA {
      PromiseState: 'rejected',
      PromiseResult: 'error',
      callbacks: []
    }
    PromiseA {
      PromiseState: 'fulfilled',
      PromiseResult: 'OK',
      callbacks: []
    }
    PromiseA {
      PromiseState: 'fulfilled',
      PromiseResult: 111,
      callbacks: []
    }
    
    

    13.Promise.reject 的封装

    它和resolve的区别就是 无论是什么情况下,它的返回结果的Promise都是失败的情况的.

    //添加 reject 方法
    PromiseA.reject = function (value){
        //返回Promise
        return new PromiseA((resolve,reject)=>{
             reject(value)
        })
    }
    

    14.Promise.all 的封装实现

    它的特性是什么是什么? 它的参数是一个数组,里面是promise对象.
    只有所有的promise对象都成功,它才会成功,但是如果其中有一个失败,那么结果就会失败.

    下面是实现方法:

    //添加 all 方法
    PromiseA.all = function (promises){
        //返回结果为Promise的对象
        return new PromiseA((resolve,reject)=>{
            //遍历
            let count = 0;
            let arr = [];
            for(let i = 0;i<promises.length;i++){
                promises[i].then(v=>{
                    //得知对象的状态是成功
                    //每个promise对象都成功
                    count++;
                    //将当前promise对象成功的结果 存入到数组中
                    // arr.push(v);
                    arr[i] = v;
                    if(count === promises.length){
                        resolve(arr);
                    }
                },r=>{
                    reject(r);
                });
            }
        })
    }
    

    测试用例: 成功的情况

    let p = PromiseA.resolve("ok");
    let p1 = PromiseA.resolve("111");
    let p2 = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
            resolve("ccc")
        },1000)
    })
    
    let p3 = PromiseA.all([p,p1,p2]);
    p3.then((data)=>{
        console.log(data);
    })
    

    输出结果:

    [ 'ok', '111', 'ccc' ]
    

    测试用例:失败的情况

    let p = PromiseA.resolve("ok");
    let p1 = PromiseA.resolve("111");
    let p2 = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
            reject("error");
        },1000)
    })
    
    let p3 = PromiseA.race([p,p1,p2]);
    p3.catch(e=>{
        console.log(e)
    })
    //输出
    //error
    

    15 Promise.race 的封装

    它的特性是,只要其中有一个成功,那么就成功,并返回这个结果,
    如果其中有一个就失败了,那么就失败了,返回失败的结果,有别去上面的情况.不需要计数 直接有结果就调用.

    PromiseA.race = function (promises){
        return new PromiseA((resolve,reject)=>{
            for(let i = 0;i<promises.length;i++){
                promises[i].then(v=>{
                    resolve(v);
                },r=>{
                    reject(r);
                });
            }
        })
    }
    
    

    测试用例:

    let p = PromiseA.resolve("ok");
    let p1 = PromiseA.resolve("111");
    let p2 = new PromiseA((resolve,reject)=>{
        setTimeout(()=>{
            reject("111");
        },1000)
    })
    
    let p3 = PromiseA.race([p,p1,p2]);
    p3.then(v=>{
        console.log(v)
    })
    
    //输出
    ok
    

    16. 回调函数时异步执行的

    这里附上完整的代码:

    function PromiseA(executor){
        //添加属性
        this.PromiseState = "pending";
        this.PromiseResult = null;
        this.callbacks = [];
        //预先保存实例对象的this值
        const self = this;
        
        //resolve函数
        function resolve(data){
            //判断状态
            if(self.PromiseState !== "pending"){
                return ;
            }
            //1.修改对象的状态(PromiseState)
            self.PromiseState = "fulfilled";
            //2.设置对象的结果值(PromiseResult)
            self.PromiseResult = data;
            //微任务执行回调
            queueMicrotask(()=> {
                //调用成功的回调函数
                self.callbacks.forEach(item => {
                    item.onResolved(data);
                })
            })
        }
        function reject(data){
            //判断状态
            if(self.PromiseState !== "pending"){
                return ;
            }
            //1.修改对象的状态(PromiseState)
            self.PromiseState = "rejected";
            //2.设置对象的结果值(PromiseResult)
            self.PromiseResult = data;
            //微任务执行回调
            queueMicrotask(()=> {
                    //调用失败的回调函数
                    self.callbacks.forEach(item => {
                        item.onRejected(data);
                    })
                }
            )
        }
        //处理 throw 抛出的错误
        try{
            //同步调用一下
            executor(resolve,reject);
        }catch (e){
            //通过调用reject函数,它的内部可以修改状态的和赋值
            //所以我们这里可以把错误直接传进去就可以了.
            reject(e);
        }
    }
    //添加 then 方法
    PromiseA.prototype.then = function (onResolved,onRejected){
        const self = this;
        
        //判断回调函数参数
        if(typeof onRejected !== 'function'){
            onRejected = reason => {
                throw reason
            }
        }
        if(typeof onResolved !== "function"){
            onResolved = value => value;
        }
        
        //这个就是返回外部的结果Promise ,它的内部状态由 then方法的回调决定
        return new PromiseA((resolve,reject)=>{
            //抽象成一个函数
            function callback(type){
                try{
                    let result = type(self.PromiseResult);
                    //判断 result 是 Promise 对象
                    if(result instanceof PromiseA){
                        //如果是Promise对象,我们需要知道这个对象的状态是成功还是失败的?
                        //Promise对象如果成功,它一定会回调 onResolved 失败 会回调 onRejected
                        result.then(v=>{
                            //在它的内部调用 resolve 来修改外部 我们创建的那个Promise对象的状态
                            resolve(v);
                        },r=>{
                            reject(r);
                        })
                    }else{
                        //非Promise 数据 则成功,通过调用resolve来修改
                        resolve(result);
                    }
                }catch (e){
                    reject(e);
                }
            }
            
            //调用 成功 回调函数
            if(self.PromiseState === "fulfilled"){
                queueMicrotask(()=> {
                    callback(onResolved);
                })
            }
            //调用失败的回调函数
            if(self.PromiseState === "rejected"){
                queueMicrotask(()=> {
                    callback(onRejected);
                })
            }
            //添加pending状态的处理
            if(self.PromiseState === "pending"){
                //保存回调函数
                self.callbacks.push({
                    onResolved:function (){
                        queueMicrotask(()=> {
                            callback(onResolved);
                        });
                    },
                    onRejected:function (){
                        queueMicrotask(()=> {
                            callback(onRejected);
                        })
                    }
                });
            }
        })
    }
    //添加catch方法
    PromiseA.prototype.catch = function (onRejected){
        return this.then(undefined,onRejected)
    }
    //添加 resolve 方法
    PromiseA.resolve = function (value){
        //返回Promise
        return new PromiseA((resolve,reject)=>{
            try{
                if(value instanceof PromiseA){
                    value.then(v=>{
                        resolve(v);
                    },r=>{
                        reject(r);
                    })
                }else{
                    resolve(value);
                }
            }catch (e){
                reject(e);
            }
        })
    }
    //添加 reject 方法
    PromiseA.reject = function (value){
        //返回Promise
        return new PromiseA((resolve,reject)=>{
            try{
                reject(value)
            }catch (e){
                reject(e);
            }
        })
    }
    //添加 all 方法
    PromiseA.all = function (promises){
        //返回结果为Promise的对象
        return new PromiseA((resolve,reject)=>{
            //遍历
            let count = 0;
            let arr = [];
            for(let i = 0;i<promises.length;i++){
                promises[i].then(v=>{
                    //得知对象的状态是成功
                    //每个promise对象都成功
                    count++;
                    //将当前promise对象成功的结果 存入到数组中
                    // arr.push(v);
                    arr[i] = v;
                    if(count === promises.length){
                        resolve(arr);
                    }
                },r=>{
                    reject(r);
                });
            }
        })
    }
    // 添加race方法
    PromiseA.race = function (promises){
        return new PromiseA((resolve,reject)=>{
            for(let i = 0;i<promises.length;i++){
                promises[i].then(v=>{
                    resolve(v);
                },r=>{
                    reject(r);
                });
            }
        })
    }
    

    测试用例:

    let p = new PromiseA((resolve,reject)=>{
        console.log('111')
        resolve("222")
    })
    console.log(333)
    p.then((value)=>{
        console.log(value)
    })
    
    输出结果:
    111
    333
    222
    
    

    相关文章

      网友评论

          本文标题:不积跬步之手写Promise源码(下)

          本文链接:https://www.haomeiwen.com/subject/egjhdrtx.html