本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-12-15
等待者模式(Waiter):通过对多个异步进程监听,来触发未来发生的动作。
var Waiter = function () {
// 注册了的等待对象容器
var dfd = [];
var doneArr = []; // 成功回调方法容器
var failArr = []; // 失败回调方法容器
var that = this;
// 监控对象类
var MyPromise = function() {
this.resolved = false;
this.rejected = false;
}
MyPromise.prototype = {
resolve: function() {
// 设置当期监控对象成功解决
this.resolved = true;
// 没有监控对象则取消执行
if (!dfd.length) {
return;
}
// 在所有监控对象都被解决时(监控的所有异步任务都resolve)才会执行_exec
for (var 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() {
this.rejected = true;
if (!dfd.length) {
return;
}
// 清除所有的监控对象
dfd.splice(0);
// 执行所有的失败回调
_exec(failArr);
},
}
// 创建监控对象
that.Deferred = function () {
return new MyPromise();
}
// 回调执行方法
function _exec(arr) {
for(var i = 0, len = arr.length; i < len; i++) {
try {
arr[i] && arr[i]();
} catch (error) {
}
}
};
// 监控异步方法 参数:监控对象
that.when = function() {
dfd = Array.from(arguments);
for (var i = dfd.length - 1; i >= 0; i--) {
// 如果不存在监控对象,或者监控对象已解决,或者不是监控对象,就移除
if (!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof MyPromise) {
dfd.splice(i, 1)
}
}
return that;
};
// 添加成功回调
that.done = function() {
doneArr = doneArr.concat(Array.from(arguments));
return that;
}
// 添加失败回调
that.fail = function() {
failArr = failArr.concat(Array.from(arguments));
return that;
}
}
var waiter = new Waiter();
var first = (function () {
// 创建监听对象
var dtd = waiter.Deferred();
setTimeout(() => {
console.log('first finish')
// 发送解决成功消息
dtd.resolve();
}, 1000)
return dtd;
})();
var second = (function () {
// 创建监听对象
var dtd = waiter.Deferred();
setTimeout(() => {
console.log('second finish')
// 发送解决成功消息
dtd.resolve();
}, 3000)
return dtd;
})();
// 用等待者对象监听两个异步任务
waiter
.when(first, second)
.done(function() {
console.log('success')
}, function() {
console.log('success again')
})
.fail(function() {
console.log('fail')
})
等待者模式可以监听多个异步任务执行成功与否,并可执行响应的回调函数处理,在实战中,意在处理耗时比较长的操作,比如 canvas 中遍历并操作一张大图片中每一个像素点、定时器操作、异步请求等。等待者模式为我们提供了一个抽象的非阻塞方法,只是当异步任务没有全部都“resolved”时,将已经“resolved”的异步任务存储暂时不作处理,只有当所有的异步任务都“resolved”(每个异步任务执行resolve时,都会遍历所有被监听的异步任务,是否都被“resolved”了),才执行注册的成功回调或失败回调。
除此之外,轮询实现的机制也有类似等待者模式,只不过是在其自身内部对未来动作进行了监听。
(function getAjaxData() {
// 保存当前函数
var fn = arguments.callee;
setTimeout(function() {
$.get('./test.php', function() {
console.log('轮询一次');
fn(); // 再一次执行轮询
})
}, 5000)
})()