實現一個完整的promise

junyu-node發表於2018-06-21

promise 是什麼

Promise 是為了解決非同步回撥問題,處理非同步回撥使得程式碼層次更加清晰,便於理解,更加容易維護
複製程式碼

首先我們簡單實用一個一下es6的promise 然後去簡單實現一下,用setTimeout 簡單的模擬非同步

    function fn1(resolve,reject){
        setTimeout(()=>{
            console.log(1)
            resolve(1);
        })
    }

    

    new Promise(fn1).then((data)=>{
        console.log('data:'+data); // data : 1
        
    })

        // 結果是先打出一個1 然後在打出 data: 1
複製程式碼

簡單的實現上邊程式碼的promise

- 首先Promise 是一個函式 有兩個引數 resolve 和 reject 一個成功的引數一個失敗的引數
- promise 有三個狀態  pending 等待態 fulfilled 成功態 rejected 失敗態
- 如果 函式沒有返回成功或者失敗 那麼 他一直就是等待態, 需要兩個陣列把函式存起來,等待他的狀態變化 再去執行相對的函式 設定兩個陣列 一個為 成功的陣列 onResolvedCallbacks 一個為失敗的陣列 onRejectedCallbacks
- promise 一旦成功 就不能 失敗  一旦失敗就不能成功 不能進行轉換 所以執行成功或者失敗的函式時 要判斷是不是 等待態 如果是等待態 在去執行 成功或失敗的函式 並且把其變成響應的狀態,把其值 改變,並且執行回撥函式
複製程式碼
 class Promise{
     constructor(exectour){
         this.status="pending" //定義狀態
         this.onResolvedCallbacks=[]; // 成功函式的陣列
         this.onRejectedCallbacks=[];   // 失敗函式的陣列
         this.value=undefined; //成功的返回值
         this.season=undefined; //失敗的返回值
         let resolve=(value)=>{ // 成功的回撥函式
            if(this.status==='pending'){
                this.status='fulfilled';
                this.value=value;
                this.onResolvedCallbacks.forEach(fn=>fn(this.value))
            } 
         }
         let reject=(reason)=>{ 失敗的回撥函式
           if(this.status==='pending'){
                this.status='rejected';
                this.reason=reason;
                this.onRejectedCallbacks.forEach(fn=>fn(this.reason))
            }    
         }
        exectour(resolve,reject);
     }
 }
 module.exports=Promise;

複製程式碼

上邊程式碼的then 方法

- then 的引數有兩個,第一個引數是成功的引數 onFulfilled,第二個引數是失敗的引數 onRejected
- 執行到then 的時候 有三個狀態  成功 失敗 和等待  成功的時候執行成功的函式 失敗的時候執行失敗的函式,等待的時候就存到他們各自函式的陣列裡邊
複製程式碼
class Promise{
    constructor(exectour){
        //code
    }
    then(onFulfilled,onRejected){
        
        if(this.status==='fulfilled'){//成功態
            onFulfilled(this.value)
            
        }
        
        if(this.status==='rejected'){//失敗態
            this.onRejected(this.reason)
        }
        
        if(this.status==='pending'){//等待態
            this.onResolvedCallbacks.push(onFulfilled);  
            this.onRejectedCallbacks.push(onRejected);
        }
    }
    
}
module.exports=Promise;
複製程式碼

完整程式碼


class Promise{
    constructor(exectour){
         this.status="pending" //定義狀態
         this.onResolvedCallbacks=[]; // 成功函式的陣列
         this.onRejectedCallbacks=[];   // 失敗函式的陣列
         this.value=undefined; //成功的返回值
         this.season=undefined; //失敗的返回值
         let resolve=(value)=>{ // 成功的回撥函式
            if(this.status==='pending'){
                this.status='fulfilled';
                this.value=value;
                this.onResolvedCallbacks.forEach(fn=>fn(this.value))
            } 
         }
         let reject=(reason)=>{ 失敗的回撥函式
           if(this.status==='pending'){
                this.status='rejected';
                this.reason=reason;
                this.onRejectedCallbacks.forEach(fn=>fn(this.reason))
            }    
         }
        exectour(resolve,reject);
     }
     then (onFulfilled,onRejected){
        
        if(this.status==='fulfilled'){//成功態
            onFulfilled(this.value)
            
        }
        
        if(this.status==='fulfilled'){//失敗態
            this.onRejected(this.reason)
        }
        
        if(this.status==='pending'){//等待態
            this.onResolvedCallbacks.push(onFulfilled);  
            this.onRejectedCallbacks.push(onRejected);
        }
    }
 }

module.exports=Promise;
複製程式碼

使用 自己寫的promise


 const Promise= require('./Promise');

 function fn1(resolve,reject){
        setTimeout(()=>{
            console.log(1)
            resolve(1);
        })
    }

    

    new Promise(fn1).then((data)=>{
        console.log('data:'+data); // data : 1
        
    },reason=>{
		console.log('raeson'+reson)
	})

複製程式碼

總結 這就簡單實現了一個漏洞百出的promise ,後邊將繼續完善我們promise ,上邊的promise如果回撥的時候 丟擲一個異常那麼我們現在實現的promise 是不會做出反應的所以要考慮一下這種情況

class Promise{
    constructor(exectour){
        //code
        
        try{
             exectour(resolve,reject);
        }catch(e){
            reject(e);
        }
    }
    
}


複製程式碼

我們目前完成的promise 是不能鏈式的 所以下一步就是實現鏈式,要想實現鏈式 那麼 回撥函式返回的就是一個promise 才會現實鏈式

根據 promise a+的規範 返回一個名字叫 promise2 的一個promise
x 是回撥函式的返回值,要看看 是不是promise 如果是 取他的結果,作為promise2 成功的結果
如果返回的是一個普通值, 作為promise2 成功的結果

然後我們用 resilvePromise 解析 x 和promise2 之間的關係
複製程式碼
class Promise{
    constructor(exectour){
        //code
        
       
    }
    then(onFulfilled,onRejected){
        let promise2
        if(this.status==='fulfilled'){//成功態
            promise2=new Promise((resolve,reject)=>{
                let x= onFulfilled(this.value);
                resolvePromise(promise2,x,resolve,reject)
            })
            
            
        }
        
        if(this.status==='fulfilled'){//失敗態
            
            promise2=new Promise((resolve,reject)=>{
                let x= this.onRejected(this.reason)
                resolvePromise(promise2,x,resolve,reject)
            })
        }
        
        if(this.status==='pending'){//等待態
            promise2=new Promise((resolve,reject)=>{
                this.onResolvedCallbacks.push(()=>{
                    let x=onFulfilled(this.value)
                    resolvePromise(promise2,x,resolve,reject)
                    
                });  
                this.onRejectedCallbacks.push(()=>{
                    let x= this.onRejected(this.reason)
                    resolvePromise(promise2,x,resolve,reject)
                });
            })
            
            
        }
        return promise2 // 呼叫then後返回一個新的promise
        
    }
    
}
複製程式碼

那麼我們接下來實現 resolvePromise解析 x 和promise2 之間的關係

function resolvePromise(promise2,x,resolve,reject){
   // 首先判斷promise2 和x 是不是同一個promise 如果是報錯
   if(promise2===x){
       reject(new TypeError('迴圈引用'))
   }
   
   //如果x不是null 並且 是物件或者函式 我們進進一步去做處理 否則我們 認為他是一個值 直接傳成功就可以了
   if(x!==null && (typeof x === 'object' || typeof x ==='function')){
       // 
       let called //防止成功或失敗再去呼叫
       
       try{  //防止取的then 出現異常
            let then=x.then
            
            if(typeof then=='function'){//如果then 是一個函式我們就認為他是一個promise
            then.call(x,y=>{ // call 第一個引數是this ,後面的是成功的回撥和失敗的回撥
                //y 是promise就繼續遞迴解析
                if(called) return false;
                called= true;
                resolvePromise(promise2,y,resolve,reject);
            },r=>{
                if(called) return false;
                called= true;
                reject(r)
                
            })
                
            }else{
                resolve(x) //then shi 一個普通物件 就直接成功   
            }
           
       }catch(e){
           if (called) return;
          called = true;
          reject(e);
       }
       
       
   }else{
       resolve(x);
   }
}


複製程式碼

那麼 我們基本上就完成了一個promise 不過promise 的幾個方法還沒有實現 那麼我們繼續完成promise上的另幾個方法

class Promise {
    //code
    catch(onRejected) {
     // catch就是then的沒有成功的簡寫
     return this.then(null, onRejected);
   }
}
Promise.resolve = function (val) {
 return new Promise((resolve, reject) => resolve(val))
}
Promise.reject = function (val) {
return new Promise((resolve, reject) => reject(val));
}
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
 for (let i = 0; i < promises.length; i++) {
   promises[i].then(resolve, reject);
 }
});
}
Promise.all = function (promises) {
return new Promise((resolve,reject)=>{
 let arr = [];
 let i = 0; // i的目的是為了保證獲取全部成功,來設定的索引
 function processData(index,data) {
   arr[index] = data;
   i++;
   if (i === promises.length){
     resolve(arr);
   }
 }
 for(let i = 0;i<promises.length;i++){
   promises[i].then(data=>{
     processData(i,data);
   }, reject);
 }
})
}
Promise.deferred = Promise.defer = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
 dfd.resolve = resolve;
 dfd.reject = reject;
})
return dfd;
}
複製程式碼

這就基本完成了一個promise 程式碼和語言的歸納還比較稚嫩,希望大家多多指點。

相關文章