淺析promise與自定義promise

重點寫在開頭吧。
promise 簡單用法promise

new Promise ((res, rej) => {執行函數; res(data)}).then(data => 處理(data))

傳統觀念上拆分異步

1. new Promise -> 實例化過程
   2.(res, rej) => {執行函數; res(data)} -> 執行函數並拋出數據
   3.then(data => process(data)) -> 處理拋出值

可是 實際上 then 主要是用來 聲明回調函數,回調函數的執行通常都是在實例化的時候
(由於實例化傳入的函數不少都是異步,執行慢;這有點相似於觀察者模式,在subscribe中去聲明回調,真正的執行實際上在next的時候)
因此:
通常實際執行順序拆分(按照執行速度拆分排序)函數

1.new Promise -> 實例化過程
    2.then(data => process(data)) -> 聲明回調函數
    3.(res, rej) => {執行函數; res(data)} -> 用then 中聲明的回調函數 處理 這個res拋出的data

可是還有一種狀況,就是實例化時候的執行函數處理速度超過了then的聲明(按照執行速度拆分排序)this

1. new Promise -> 實例化過程
   2.(res, rej) => {執行函數; res(data)} -> 執行函數並拋出數據,而且then還沒有聲明完成
   3.then(data => process(data)) -> 直接執行函數

簡單點說,就是實例化時候,傳入的函數,和 then 聲明,到底誰先完成這是promise惟一的難點。
這麼說,若是「執行函數「 執行完成,執行res(data)時,then還沒聲明完,那麼回調函數就會爲空,這個時候就得讓then 中 回調函數在聲明完成的以後直接執行
亦或者 ,then 聲明完成時候,尚未res(data), 那麼就得讓then 中聲明的方法先加入到一個隊列,等待res(data)時候依次執行;線程

若是這邊沒有看懂的話,能夠繼續往下看。有形象化的解釋。code

promise的用法簡單介紹一下,我以爲若是有人願意看這篇文章,對promise的用法多多少少也瞭解;排序

new Promise((res, rej) => {
        try{
            執行函數;
            res(data)
        } catch(e){
            rej(e);
        }}).then(resCb, rejCb).then(cb);

先說下我我的對promise的理解隊列

1.promise 從表現形式上看,是將執行函數的返回值經過resolve或者reject 拋出data,再在then 函數裏面處理data
2.promise 能夠鏈式調用then,上一個then的返回值做爲下一個then中函數的實參回調函數

但實際上,promise 並不是必定是在then 裏面執行的,尤爲是異步的時候,理應在實例函數中執行,才符合咱們對單線程的理解。it

promise簡單點說分爲兩部分。一個是實例化 時候,傳入的執行函數另外一部分爲then中傳入的回調函數 這個關係就比如 監考老師學生
若是監考老師 先到了教室,那麼天然而然,學生是直接依次進入教室;(實例函數執行較快,超過了then的聲明)
若是監考老師 在學生們後面到,那麼學生們只能按順序排隊在門口等監考老師;(實例函數執行較慢)
也就是說,執行函數和then函數的聲明,前後順序並不是固定(通常狀況下then聲明先完成)
這個時候就須要一個狀態碼去判斷究竟是哪一種狀況('default', 'resolve' ,'reject')
爲了方便理解,能夠把resolve 和 reject當作同一類型
我先直接發代碼寫註釋
時間有限,本次先不考慮then 中函數 存在異步的問題

// 簡述下邏輯:
    //1.定義一個state 是用來判斷then 和 實例化時候傳入的函數 哪個先完成
    //也就是剛剛說的監考老師和學生的問題。默認值爲default, 默認老師沒到(實例函數未執行完成)
    //2.定義resolve_ 用來存放then 中定義的方法,至關於學生排隊的過道,便於按順序執行,reject_同理,如下再也不重複
    //3.定義resolveData用來記錄拋出值,也就是res(data) 中的data,做爲then中方法的參數
    //4.在res拋出值的時候,將state改爲resolve,至關於代表監考老師到教室了
      //若是resolve_隊列中已經有定義函數就依次執行它們,至關於若是有學生就進教室。
    //5.then 方法聲明時候,檢測狀態state 是否是 default ,若是是,說明尚未拋出值,
      //至關於監考老師還沒到,學生都去排隊,加入到resolve_隊列; 
      //若是狀態已經不是default ,那麼說明監考老師已經到了,學生不用排隊,直接進教室;也就是方法直接執行
  
new promise_( (res, rej) => res(3)).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6

針對實際例子說一下
上面的例子明顯就是 res(3) 先執行完成,而後執行then 的函數
至關於監考老師先到了教室,那麼,then 中的定義的函數就應該直接執行

new promise_( (res, rej) => setTimeout( () => res(3), 1000).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6

上面的例子明顯就是 then 先定義完成,而後res才拋出值
至關於監考老師後到了教室,那麼,then 中的定義的函數就應該默默排隊等待

由於 then 和 實例函數 二者順序並不肯定,因此 then 時候要經過state 判斷實例函數 是否執行完成,
同時,實例函數執行完成拋出值時,也須要檢測一下resolve_隊列,判斷then 是否已經聲明完成。
下面是我本身寫的promise的代碼

class promise_ {

    constructor(func) {

        if(typeof func !== 'function'){
            throw Error('實例化中傳參必須爲函數');
            return;
        } // 判斷下是否傳入的是函數 ,與邏輯無關,直接往下看

        this.state = 'default'; //用來判斷
        this.resolve_ = []; // then中reslove 的方法隊列,用來接收resolve方法
        this.reject_ = []; // then中的reject 的方法隊列,用來接收reject方法
        this.resolveData = null; // resolve的拋出值
        this.rejectData = null; // reject的拋出值 

        func(this.resolve.bind(this), this.reject.bind(this)); //實例化時候傳入的函數

    }
    
    then(cb, errCb) {

        if(typeof cb !== 'function' || (errCb && typeof cb !== 'function')) {
            throw Error('then參數,成功回調函數,失敗回調函數');
            return;
        } // 平常判斷是否是傳參正確,和邏輯無關

        switch(this.state) { // 檢測一下監考老師來沒來教室
            case 'default': this.resolve_.push(cb); this.reject_.push(errCb); break;// 若是監考老師沒到場,排隊
            case 'resolve': this.resolveData = cb(this.resolveData); break; // 若是監考老師到場,直接進來,由於鏈式調用,因此執行後把拋出值改一下,方便後面的then 用
            case 'reject': this.rejectData = errCb(this.rejectData); break;// 若是監考老師到場,直接進來,由於鏈式調用,因此執行後把拋出值改一下,方便後面的then 用
            default: break; 
        }

        return this; // 鏈式調用
    }

    resolve(data) {

        if(!data) return; // 判斷有無參數,和邏輯無關

        this.resolveData = data; // 設定拋出值
        this.state = 'resolve'; // 將狀態設置爲resolve ,表示監考老師到場了
        while(this.resolve_.length)  // 先進先出,依次執行then 中函數
            this.resolvedata = this.resolve_.shift()(data);
    }

    reject(data) {

        if(!data) return;

        this.rejectData = data;
        this.state = 'reject';
        while(this.reject_.length) 
            this.rejectData = this.reject_.shift()(data);
    }

}
相關文章
相關標籤/搜索