基於promise /A+規範手寫promise

Liysuo發表於2019-04-09

什麼是promise

promise是一個類,是現在比較常用的一個非同步解決方案,用來解決之前非同步程式設計的回撥地獄問題

常見的幾種非同步程式設計方法

  • 回掉函式
  • 事件監聽
  • 釋出訂閱
  • promise
  • generator(一般不用)
  • async、await(es8語法)

promise和回撥函式對比

promise版
let api = new Promise((resolve,reject)=>{
    
    resolve("成功");
    reject("失敗")
})

api
.then(val=>{
    resolve(val)
})
.then(val=>{
    resolve(val)
})
.then(val=>{
    console.log(val)  // 成功
})

使用回撥函式
$.get(url, data1 => {
    console.log(data1)
    $.get(data1.url, data2 => {
        console.log(data1)
    })
})



複製程式碼

這樣看起來是不是更加清晰了

promise的使用

  • Promise 是一個建構函式, new Promise 返回一個 promise物件 接收一個excutor執行函式作為引數, excutor有兩個函式型別形參resolve reject
// excutor函式會立即執行,引數是resolve和reject函式
// 每個promise例項都有一個then方法
let promise = new Promise(function(resolve,reject){//excutor
    resolve("成功");
    reject("失敗")
})

//onfulfilled 成功, onrejectd 失敗
promise.then(function(val){  //onfulfilled
    console.log(val) //成功
},function(err){  //onrejectd 
    console.log(err) //失敗
})
複製程式碼

promise有三個狀態

  • pendding 等待狀態、resolved 成功態、rejected 失敗態

1.pendding 等待狀態 -> resolved 成功態
2.pendding 等待狀態 -> resolved 成功態

**注意:成功態和失敗態不能相互轉化,只能由 pending => fulfilled/rejected, 一旦修改就不能再變

promise物件方法**

手寫promise程式碼

function Promise(executor){
    // promise 有三個狀態 pending  fulfilled rejected
    this.status = 'pending'; // 初始狀態
    this.value = undefined;  // 成功狀態時 返回的資訊
    this.reason = undefined; // 失敗狀態時 返回的資訊
    let self = this;
    self.onResolveCallbacks = []; // 儲存成功狀態對應的onFulfilled函式
    self.onRejectedCallbacks = []; // 儲存失敗狀態對應的onRejected函式
    function reoslve(value){ // 變成成功態
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'fulfilled';
            self.onResolveCallbacks.forEach(fn=>fn())
        }
    }
    function reject(reason){ // 變成是失敗態
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(fn=>fn())
        }
    }
    try{
        executor(reoslve,reject);
    }catch(e){
        reject(e);
    }
}
// 這個方法要相容別人的promise  嚴謹一些  這個方法 要相容別人的promise 
function resolvePromise(promise2,x,resolve,reject){
    if(promise2 === x){ // 防止返回的promise 和 then方法返回的promise 是同一個
        return reject(new TypeError('迴圈引用'));
    }
    if(x!== null && (typeof x === 'object' || typeof x === 'function')){ // {}
        let called;
        try{
            let then = x.then;  // 看看這個物件有沒有then方法,如果有 說明x是promise   {then:undefined}
            if(typeof then === 'function'){  
                then.call(x,y=>{
                    if(called) return
                    called = true;
                    // 如果返回的是一個promise這個promise,resolve的結果可能還是一個promise,遞迴解析直到這個y是一個常量為止
                    resolvePromise(promise2,y,resolve,reject)
                },r=>{
                    if(called) return // 防止呼叫失敗 又呼叫成功
                    called = true;
                    reject(r);
                });
            }else{ 
                resolve(x); // {then:{}} {then:123}
            }
        }catch(e){ // 這個then方法 是通過 ObjectDefineProperty定義的
            if(called) return
            called = true; // 這個判斷為了防止出錯後 繼續要呼叫成功邏輯
            reject(e);
        }
    }else{
        resolve(x); // x就是普通常量
    }
}
Promise.prototype.then = function(onfulfilled,onrejected){
    // 引數的可選
    onfulfilled = typeof onfulfilled ==='function'?onfulfilled :val=>val;
    onrejected = typeof onrejected == 'function'?onrejected :err=>{throw err}
    let self = this;
    // 每個promise必須返回一個新的狀態 保證可以鏈式呼叫
    let promise2 = new Promise(function(resolve,reject){
        if(self.status === 'fulfilled'){ 
            setTimeout(()=>{
                try{
                    let x = onfulfilled(self.value);
                    resolvePromise(promise2,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            })
        }
        if(self.status === 'rejected'){
            setTimeout(()=>{
                try{
                    let x = onrejected(self.reason);
                    resolvePromise(promise2,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            })
        }
        if(self.status === 'pending'){
            self.onResolveCallbacks.push(function(){ 
                setTimeout(()=>{
                    try{
                        let x = onfulfilled(self.value);
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e);
                    }
                })
            });
            self.onRejectedCallbacks.push(function(){
                setTimeout(()=>{
                    try{
                        let x = onrejected(self.reason);
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e);
                    }
                })
            })
        }
    });
    return promise2
}

// npm install promises-aplus-tests -g
// promises-aplus-tests promise.js
Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
};
module.exports = Promise
複製程式碼

相關文章