等待者模式
作用:通過對多個異步進程對監聽,對未來事件進行統一管理。在es6、7的promise等異步處理方法沒有出現前,常用等待着模式對異步事件進行管理。
function Waiter() {
// 相當於私有變量,因爲new的時候是不會把這個往實例this裏放的
var dfd = [] // 存放所有異步狀態
var doneArr = [] //存放所有成功的回調
var failArr = [] // 存放所有失敗的回調
// 註冊所有異步方法
this.when = function() {
// 獲取auguments 是一個類數組對象
// 讓類數組使用數組的方法,成爲真正的數組
dfd = Array.prototype.slice.call(arguments)
// 從後往前判斷,因爲要刪除數組元素,刪除元素後遍歷會改變
for(var i = dfd.length-1; i > 0; i--) {
var d = dfd[i]
// 判斷狀態實例是否都符合要求
if(!d || d.rejected || d.resolved || (d instanceof Defer)) {
// 剔除不符合的實例
dfd.splice(i, 1)
}
}
// 鏈式調用
return this
}
// 成功的回調
this.done = function() {
var args = Array.prototype.slice.call(arguments)
doneArr = doneArr.concat(args)
return this
}
// 失敗回調
this.fail = function() {
var args = Array.prototype.slice(arguments)
failArr = failArr.concat(args)
return this
}
this.Defered = function() {
// 創建狀態實例
return new Defer()
}
// 定義狀態類
var Defer = function() {
// 狀態值
this.resolved = false
this.rejected = false
}
Defer.prototype = {
resolve: function() {
this.resolved = true
console.log('async resolve')
for(var i = 0; i < dfd.length; i++) {
if(!dfd[i].resolved) {
return
}
// 如果全部完成,就不會return出去,則可執行下面的語句
// 執行成功的回調函數
_exec(doneArr)
}
},
reject: function() {
console.log('async reject')
this.rejected = true
// 執行失敗的回調
_exec(failArr)
}
}
// 執行回調
function _exec(arr) {
console.log('callback')
for(var i = 0; i < arr.length; i++) {
// 存在arr[i],執行
if(arr[i]) arr[i]()
}
}
}
var waiter = new Waiter()
// 創建三個異步對象
var async1 = function() {
// 創建狀態實例
var dfd = waiter.Defered()
setTimeout(function() {
console.log('async1 done')
dfd.resolve()
}, 1000)
return dfd
}
var async2 = function() {
var dfd = waiter.Defered()
setTimeout(function() {
console.log('async2 done')
dfd.resolve()
}, 1000)
return dfd
}
var async3 = function() {
var dfd = waiter.Defered()
setTimeout(function() {
console.log('async3 done')
dfd.resolve()
}, 1000)
return dfd
}
waiter.when((async1(), async2(), async3())).done(function() {
console.log('success')
}).fail(function() {
console.log('fail')
})
上述等待者模式代碼相比其他設計模式略有些複雜,在其中有一些技巧需要注意一下:
- 在註冊異步實例、判斷是否執行完畢或失敗時用到了鏈模式
return this
- 在類中用內部變量和函數構成私有變量,如
dfd
、doneArr
、failArr
- 定義內部類
Defer