libin1991 / libin_Blog

爬虫-博客大全
https://libin.netlify.com/
124 stars 17 forks source link

自己动手实现Promise #513

Open libin1991 opened 6 years ago

libin1991 commented 6 years ago

Promise是异步编程的一种解决方案,比回调函数和事件更合理更强大。

原生的promise用法如下:

let p=new Promise(function(resolve,reject){
    resolve('成功');
    //reject('失败');
});
p.then(function(data){
    console.log(data);
},function(err){
    console.log(err);
});

image Promise实例中有一个函数,接受两个参数,一个是成功的方法,一个是失败的方法,然后有一个then方法,第一个是成功执行的函数,第二个是失败执行的函数,并且会接收相应的参数。一旦执行成功,就不会再执行失败,反之亦然。

function Promise(executor){  //executor是一个执行函数
    let self = this;
    self.status = 'pending';
    self.value = undefined; //默认成功的值
    self.reason = undefined; //默认失败的值
    function resolve(value){ //成功状态
        if(self.status === 'pending'){
            self.status = 'resolved';
            self.value = value;
        }
    }
    function reject(reason){  //失败状态
        if(self.status === 'pending'){
            self.status = 'rejected';
            self.reason = reason;
        }
    }
    try{
        executor(resolve,reject);
    }catch(e){      //处理异常状态,传给reject
        reject(e);
    }
};

Promise.prototype.then = function(onFulfilled,onRejected){
    let self = this;
    if(self.status === 'resolved'){
        onFulfilled(self.value);
    }
    if(self.status === 'rejected'){
        onRejected(self.reason);
    }
};
module.exports = Promise;

首先先定义一个Promise函数,并且接受一个executor执行函数,将resolve和reject传参传进去,定义私有属性status,value,reason。 Promise有三个状态,status用来记录他们: 初始状态为pending 成功状态为resolved 失败状态为rejected

然后使用prototype挂载一个then方法, 方法中要传入一个成功的回掉和一个失败的回掉, 如果成功就调取成功的回掉, 失败就调取失败的回掉

最后将函数导出,就实现了一个最基础功能的Promise。

但是这个Promise还是一个同步的方法,如果想在代码中使用异步,比如:

let p=new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve('成功');
    },1000);
    //throw new Error('错误');
});

我们就需要将他变为异步的:

function Promise(executor){
    let self = this;
    self.status = 'pending';
    self.value = undefined;
    self.reason = undefined;
    self.onResolvedCallbacks= [];  //存放成功的回掉
    self.onRejectedCallbacks= [];  //存放失败的回掉
    function resolve(value){
        if(self.status === 'pending'){
            self.status = 'resolved';
            self.value = value;
            self.onResolvedCallbacks.forEach(function(fn){
                fn();
            });
        }
    }
    function reject(reason){
        if(self.status === 'pending'){
            self.status = 'rejected';
            self.reason = reason;
            self.onRejectedCallbacks.forEach(function(fn){
                fn();
            });
        }
    }
    try{
        executor(resolve,reject);
    }catch(e){      //处理异常状态,传给reject
        reject(e);
    }
}

Promise.prototype.then=function(onFulfilled,onRejected){
    let self = this;
    if(self.status === 'resolved'){
        onFulfilled(self.value);
    }
    if(self.status === 'rejected'){
        onRejected(self.reason);
    }
    if(self.status === 'pending'){
        self.onResolvedCallbacks.push(function(){
            onFulfilled(self.value);
        });
        self.onRejectedCallbacks.push(function(){
            onRejected(self.reason);
        });
    }
};
module.exports = Promise;

如果他是异步的,我们就不能在then方法中用status的成功失败状态来判断他走的那,因为then方法执行后有可能params中还没执行resolve或者reject,那么我们就在Promise实例上再新增onResolvedCallbacks和onRejectedCallbacks两个数组来存放他的回掉,如果执行的是成功,失败就会存默认的undefined。在调用时用forEach循环数组依次知性方法。 原生的Promise还可以then多次:

function Promise(executor){
    let self = this;
    self.status = 'pending';
    self.value = undefined;
    self.reason = undefined;
    self.onResolvedCallbacks= [];
    self.onRejectedCallbacks= [];
    function resolve(value){
        self.status = 'resolved';
        self.value = value;
        self.onResolvedCallbacks.forEach(function(fn){
            fn();
        });
    }
    function reject(reason){
        self.status = 'rejected';
        self.reason = reason;
        self.onRejectedCallbacks.forEach(function(fn){
            fn();
        });
    }

    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
};

Promise.prototype.then = function(onFulfilled,onRejected){
    let self = this;
    let promise2;           //实现链式操作
    if(self.status === 'resolved'){
        promise2 = new Promise(function(resolve, reject){
            try{
                let x = onFulfilled(self.value);
                resolve(x);
            }catch(e){
                reject(e);
            }
        });
    }
    if(self.status === 'rejected'){
        promise2 = new Promise(function(resolve, reject){
            try{
                let x = onRejected(self.reason);
                reject(x);
            }catch(e){
                reject(e);
            }
        });
    }
    if(self.status === 'pending'){
        promise2 = new Promise(function(resolve, reject){
            self.onResolvedCallbacks.push(function(){
                try{
                    let x = onFulfilled(self.value);
                    resolve(x);
                }catch(e){
                    reject(e);
                }
            });
            self.onRejectedCallbacks.push(function(){
                try{
                    let x = onRejected(self.reason);
                    reject(x);
                }catch(e){
                    reject(e);
                }
            });
        });
    }
    return promise2;
}
module.exports = Promise;

当然他then的链式调用不会有then属性,所以我们可以判断Promise每次then都会new一个新的Promise我们用Promise2来表示,then的时候new一个新的Promise并且return给下一个then。 then中无论是成功的回掉还是失败的毁掉,只要返回了结果,就会走下一个then中的成功,发生错误才会走下一个then中的失败,then中可以return普通值,也可return一个新的Promise,还有可能return 一个{then:xxx},当然更有promise.then().then.then(function(){});这种奇葩的用法

function Promise(executor){
    let self = this;
    self.status = 'pending';
    self.value = undefined;
    self.reason = undefined;
    self.onResolvedCallbacks= [];
    self.onRejectedCallbacks= [];
    function resolve(value){
        self.status = 'resolved';
        self.value = value;
        self.onResolvedCallbacks.forEach(function(fn){
            fn();
        });
    }
    function reject(reason){
        self.status = 'rejected';
        self.reason = reason;
        self.onRejectedCallbacks.forEach(function(fn){
            fn();
        });
    }
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
};

function resolvePromise(p2,x,resolve,reject){
    //1.处理乱写
    //2.判断返回的是不是自己
    if(p2 === x){
        reject(new typeError('循环引用'));
    }
    //判断x是不是params(判断x是不是object)
    let called; //表示是否调用过成功或者失败
    if(x !== null || typeof x === 'object' || typeof x === 'function'){
        //判断promise只要判断对象中是否有then方法
        try{
            letthen = x.then;
            if(typeof then === 'function'){ //then返回的可能是{then:xxx},判断then是不是一个函数
                then.call(x,function(y){ //成功了以后可能会执行resolve(new Promise())用递归来解决
                    if(called) return;
                    called = true;
                    resolvePromise(p2,y,resolve,reject);
                },function(err){
                    if(called) return;
                    called = true;
                    reject(err);
                });
            }else{
                resolve(x);
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);
        }
    }else{  //esle普通值
        resolve(x);
    }
}

Promise.prototype.then = function(onFulfilled,onRejected){  //判断onFulfilled是不是一个函数,不是给他个函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
        return value;
    }
    onRejected = typeof onRejected === 'function' ? onRejected : function(err){
        throw err;
    }
    let self = this;
    let promise2;           //实现链式操作
    if(self.status === 'resolved'){
        promise2 = new Promise(function(resolve, reject){
            let x = onFulfilled(self.value);
            resolvePromise(promise2,x,resolve,reject);
        });
    }
    if(self.status === 'rejected'){
        promise2 = new Promise(function(resolve, reject){
            let x = onRejected(self.reason);
            resolvePromise(promise2,x,resolve,reject);
        });
    }
    if(self.status === 'pending'){
        promise2 = new Promise(function(resolve, reject){
            self.onResolvedCallbacks.push(function(){
                let x = onFulfilled(self.value);
                resolvePromise(promise2,x,resolve,reject);
            });
            self.onRejectedCallbacks.push(function(){
                let x = onRejected(self.reason);
                resolvePromise(promise2,x,resolve,reject);
            });
        });
    }
    return promise2;
}
module.exports = Promise;

我们就定义一个resolvePromise来处理then中的返回结果,如果返回的是个错误信息,就用try{}catch(){}让他走reject 最后的最后,Promise中可以异步执行代码,then方法中应该也可以实现异步,很简单,只要在相应的位置加上setTimeout就ok了,记得不要忘了加上try{}catch(){}来过滤错误信息并且传到reject中

function Promise(executor){
    let self = this;
    self.status = 'pending';
    self.value = undefined;
    self.reason = undefined;
    self.onResolvedCallbacks= [];
    self.onRejectedCallbacks= [];
    function resolve(value){
        self.status = 'resolved';
        self.value = value;
        self.onResolvedCallbacks.forEach(function(fn){
            fn();
        });
    }
    function reject(reason){
        self.status = 'rejected';
        self.reason = reason;
        self.onRejectedCallbacks.forEach(function(fn){
            fn();
        });
    }
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
};

function resolvePromise(p2,x,resolve,reject){
    //1.处理乱写
    //2.判断返回的是不是自己
    if(p2 === x){
        reject(new typeError('循环引用'));
    }
    //判断x是不是params(判断x是不是object)
    let called; //表示是否调用过成功或者失败
    if(x !== null || typeof x === 'object' || typeof x === 'function'){
        //判断promise只要判断对象中是否有then方法
        try{
            letthen = x.then;
            if(typeof then === 'function'){ //then返回的可能是{then:xxx},判断then是不是一个函数
                then.call(x,function(y){ //成功了以后可能会执行resolve(new Promise())用递归来解决
                    if(called) return;
                    called = true;
                    resolvePromise(p2,y,resolve,reject);
                },function(err){
                    if(called) return;
                    called = true;
                    reject(err);
                });
            }else{
                resolve(x);
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);
        }
    }else{  //esle普通值
        resolve(x);
    }
}

Promise.prototype.then = function(onFulfilled,onRejected){  //判断onFulfilled是不是一个函数,不是给他个函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
        return value;
    }
    onRejected = typeof onRejected === 'function' ? onRejected : function(err){
        throw err;
    }
    let self = this;
    let promise2;           //实现链式操作
    if(self.status === 'resolved'){
        promise2 = new Promise(function(resolve, reject){
            setTimeout(function(){
                try{
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            })
        });
    }
    if(self.status === 'rejected'){
        promise2 = new Promise(function(resolve, reject){
            setTimeout(function(){
                try{
                    let x = onRejected(self.reason);
                    resolvePromise(promise2,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            })
        });
    }
    if(self.status === 'pending'){
        promise2 = new Promise(function(resolve, reject){
            self.onResolvedCallbacks.push(function(){
                setTimeout(function(){   
                    try{
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2,x,resolve,reject);
                    }catch(e){
                        reject(e);
                    }
                })
            });
            self.onRejectedCallbacks.push(function(){
                setTimeout(function(){
                    try{
                        let x = onRejected(self.reason);
                        resolvePromise(promise2,x,resolve,reject);
                    }catch(e){
                        reject(e);
                    }
                })
            });
        });
    }
    return promise2;
}
module.exports = Promise;