等待者模式或者等待者對象指的是多個異步邏輯沒法確認前後執行的順序以及時機時,而咱們增長對異步邏輯的監聽,當每一個異步狀態發生變化時,進行一次確認狀態,而後根據結果來決定是否執行某動做。javascript
咱們常見經常使用的Promise.all對象就是等待者模式的一種最佳實踐。前端
本文codepen地址:https://codepen.io/robinson90/pen/YzPQaoejava
let Waiter = function(){ // 定義內部的監聽對象數組,成功回調數組,失敗回調數組 let dfd = [],doneArr = [], failArr= [], slice = Array.prototype.slice,that = this; let Primise = function(){ this.resolved = false this.rejected = false } Primise.prototype = { resolve:function(){ // 設置當前對象解決 this.resolved = true //若是沒有監聽對象 直接返回 if(!dfd.length){ return } for(let i = dfd.length -1 ;i>=0;i--){ // 判斷監聽對象中是否有未解決或者解決失敗的 若是有直接返回 不執行 if(dfd[i] && !dfd[i].resolved || dfd[i].rejected){ return } // 刪除監聽對象 dfd.splice(i,1) } // 都執行完成,那麼執行回調函數的數組 _exec(doneArr) }, reject:function(){ // mark fail this.rejected = true // no dfd,return if(!dfd.length){return} // eclear all dfd dfd.splice(0) //執行失敗回調函數 _exec(failArr) } } that.Deferred = function(){ return new Primise() } // 執行回調函數數組 function _exec(arr){ let len = arr.length for(let i =0;i<len;i++){ try{ let fn = arr[i] if(fn && typeof fn === 'function'){ fn() } }catch(e){ } } } /** * @description 監控異步方法 參數爲監聽對象 */ that.when = function(){ dfd = slice.call(arguments) let i = dfd.length for(;i>=0;i--){ // 當不存在 或者 已經完成或者失敗 或者 不爲primise的實例,直接清除監控 if(!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise) { dfd.splice(i,1) } } return that } // 成功的回調函數添加方法 that.done = function(){ doneArr = doneArr.concat(slice.call(arguments)) return that } //失敗的回調函數添加方法 that.fail = function(){ failArr = failArr.concat(slice.call(arguments)) return that } }
const waiter = new Waiter() //fn1 fn2 爲兩個異步執行的方法 const first = function(){ let dfd = waiter.Deferred() setTimeout(()=>{ console.log('first finish') dfd.resolve() },1000) return dfd }() const second = function(){ let dfd = waiter.Deferred() setTimeout(()=>{ console.log('second finish') dfd.resolve() },1000) return dfd }() Waiter.when(first,second).done(()=>{ }).fail(()=>{ })
const search = function(){ window.counter =Math.random(1) console.log('查詢一次') } const longSearch = (fn,time)=>{ let timer = setInterval(()=>{ if(window.counter>0.8){ console.log('查詢結束',window.counter) clearInterval(timer) return } fn() },time) } longSearch(search,500)
封裝一個deferred對象,而後在xhr的結果返回以後使用其回調函數。git
$.ajax = function(url,success,fail){ const xhr = new XMLHttpRequest() let dfd = waiter.Deferred(); xhr.onload = function(event){ if(xhr.status>=200){ success && success() dfd.resolve() }else { dfd.reject() fail && fail() } } }
基本思路:自己也是一個異步方法,維護全部異步方法的程度+遺留長度,維護一個結果數組,每執行一個,標記一個結果,根據策略決定,是完成所有結束仍是完成一個結束,而後fullfill標記完成es6
promise.all 源碼地址:https://github.com/stefanpenner/es6-promise/blob/master/lib/es6-promise/enumerator.js github
看完等待者模式,是否是以爲這個模式其實很經常使用,設計的很巧妙,在沒有promise這個模型的時候,其實就已經出現相似的技術方案,不一樣的只是沒有定製爲一個技術規範。ajax
我是一名前端Coder,熱愛分享生活與技術中的經驗與心得。
我是一名旅遊愛好者,愛好拍攝旅途中的風景與人物。
我是一名寫做狂人,基本天天都有新文章產出,筆耕不輟。segmentfault
GitHub:http://github.com/robinson90
codepen:https://codepen.io/robinson90
personal blog: http://damobing.com
yuque docs: https://www.yuque.com/robinson
juejin blog: https://juejin.im/user/5a30ce...數組
微信:csnikey,或者掃碼加我promise
達摩空間訂閱號:damo_kongjian,或者掃描下面的二維碼