重點寫在開頭吧。
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); } }