等待者模式
作用:通过对多个异步进程对监听,对未来事件进行统一管理。在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