根據Promises/A+規範實現一個原生Promise

context發表於2018-01-15

Promise表示一個非同步操作的最終結果。與Promise最主要的互動方法是通過將函式傳入它的then方法從而獲取得Promise最終的值或Promise最終最拒絕(reject)的原因。

Promise解決的問題是以往在js函式中使用回撥函式的問題。 沒有Promise之前:

function personInfo(callback){
    //dosometing
    callback&&callback();
}
複製程式碼

原生Promise用法

let p=new Promise((resolve,reject)=>{
    resolve('123');
});
p.then(data=>{console.log(data)});
複製程式碼

按照Promise/A+規範來實現一個Promise類。
Promise有三個狀態:pending, fulfilled 或 rejected。
初始化狀態為pending
成功狀態為fulfilled
失敗狀態rejected
self.value存放的是成功的值
self.reason存放的是失敗的值
self.onResolvedCallbacks存的是所有成功回撥的值
self.onRejectedCallbacks存的是所有失敗回撥的值

function Promise(executor){
    let self=this;
    self.status='pending';
    self.value=undefined;
    self.reason=undefined;
    self.onResolvedCallbacks=[];
    self.onRejectedCallbacks=[];
    function resolve(value){
        //new Promise(new Promise((resolve,reject)=>resolve()));
        if(value!=null &&value.then&&typeof value.then == 'function'){
            return value.then(resolve,reject);
        }
        setTimeout(function(){
            if(self.status=='pending'){
                self.status='fulfilled';
                self.value=value;
                self.onResolvedCallbacks.forEach(item=>item(self.value));
            }
        });
    }
    function reject(reason){
        setTimeout(function(){
            if(self.status=='pending'){
                self.status='rejected';
                self.reason=reason;
                self.onRejectedCallbacks.forEach(item=>item(self.reason));
            }
        });
    }
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}
複製程式碼

建構函式原型上的then方法,通過狀態獲取值。返回一個新的Promise例項。

Promise.prototype.then=function(onFulfilled,onRejected){
    onFulfilled=typeof onFulfilled=='function'?onFulfilled:value=>value;
    onRejected=typeof onRejected=='function'?onRejected:reason=>{throw reason};
    let self=this
    let promise2;
    if(self.status=='resolve'){
        return promise2=new Promise((resolve,reject)=>{
            try{
                let x=onFulfilled(self.value);
                resolvePromise(promise2,x,resolve,reject);
            }catch(e){
                reject(e)
            }
        });
    }
    if(self.status=='reject'){
        return promise2=new Promise((resolve,reject)=>{
            try{
                let x = onRejected(self.reason);
                resolvePromise(promise2, x, resolve, reject);
            }catch(e){
                 reject(e)
            }
        });
    }
    if(self.status=='pending'){
        return promise2 = new Promise(function (resolve, reject) {
            self.onResolvedCallbacks.push(()=>{
                try {
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                 }
            });
            self.onRejectedCallbacks.push(()=>{
                try {
                    let x = onRejected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            });
        })
    }
}
複製程式碼

錯誤捕獲,走失敗的回撥函式

Promise.prototype.catch = function(onRejected){
    this.then(null,onRejected);
}
複製程式碼

Promise.all所有的Promise執行完,再執行下一步。接受的引數是個陣列,返回有一個新的Promise例項。陣列中的每一項必須為成功態,then得到的值也會依次按順序排列在陣列中

Promise.all=function(promises){
    return new Promise((resolve,reject)=>{
        let result=[];
        let count=0;
        let len=promises.length;
        for(let i=0;i<promises.length;i++){
            promises[i].then((data)=>{
                result[i]=data;
                if(++count==len){
                    resolve(result);
                }
            },reject);
        }
    });
}
複製程式碼

Promise.race一個Promise執行完,就執行下一步。接受的引數是個陣列,返回有一個新的Promise例項。

Promise.race = function(promises){
    return new Promise(function(resolve,reject){
        for(let i=0;i<promises.length;i++){
            promises[i].then(resolve,reject);
        }
    });
}
複製程式碼

Promise.resolve返回一個成功態的Promise例項

Promise.resolve = function(value){
    return new Promise(function(resolve,reject){
        resolve(value);
    });
}
複製程式碼

Promise.reject返回一個失敗態的Promise例項

Promise.reject = function(reason){
    return new Promise(function(reresolve,reject){
        reject(reason);
    });
}
複製程式碼

相關文章