Promise原理解析

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方法,第一個是成功執行的函數,第二個是失敗執行的函數,而且會接收相應的參數。一旦執行成功,就不會再執行失敗,反之亦然。promise

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                     失敗狀態爲rejectedbash

而後使用prototype掛載一個then方法,                     方法中要傳入一個成功的回掉和一個失敗的回掉,                     若是成功就調取成功的回掉,                     失敗就調取失敗的回掉異步

最後將函數導出,就實現了一個最基礎功能的Promise。異步編程

可是這個Promise仍是一個同步的方法,若是想在代碼中使用異步,好比:函數

let p=new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve('成功');
    },1000);
    //throw new Error('錯誤');
});
複製代碼

咱們就須要將他變爲異步的:ui

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屢次:this

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(){});這種奇葩的用法spa

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{
            let then = 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{
            let then = 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;
複製代碼
相關文章
相關標籤/搜索