等待者模式
等待者模式是通过对多个异步任务进行监听,当异步任务完成后触发未来发生的动作,在没有Promise
这个模型的时候,其实就已经出现这样类似的技术方案,不同的只是没有定制为一个技术规范,等待者模式不属于一般定义的23
种设计模式的范畴,而通常将其看作广义上的技巧型设计模式。
描述
等待者模式就是通过对异步进程监听,来触发未来发生的动作,举个例子当异步进程操作A、B
需要都完成以后才能进行C
进程操作,在开发中经常会这样,需要等到上个操作完成或者知道上个操作完成才去触发下个操作,而JavaScript
又是单线程的,不能采用阻塞的方式去处理,在Promise
规范出现之前通常都是使用回调的方式实现,这样很容易造成回调地狱,等待者模式就是在Promise
规范制定之前一个类似于Promise
的解决方案,可以算是Promise
规范的一个参考前身。
实现
var Waiter = function() {
var dfd = []; // 等待对象容器
var doneArr = []; // 成功回调容器
var failArr = []; // 失败回调容器
//监控对象类
var Promise = function() {
this.resolved = false; // 监控对象是否解决成功状态
this.rejected = false; // 监控对象是否解决失败状态
}
Promise.prototype = {
//解决成功
resolve: function() {
this.resolved = true; // 设置当前监控状态是成功
if (!dfd.length) return void 0;
for (var i = dfd.length - 1; i >= 0; i--) {
// 对象监控对象遍历如果任一个对象没有解决或者失败就返回
if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) return void 0;
dfd.splice(i, 1);
}
_exec(doneArr);
},
//解决失败
reject: function() {
this.rejected = true; // 设置当前监控状态是失败
if (!dfd.length) return void 0; // 没有监控对象取消
dfd.splice(0); // 清除监控对象
_exec(failArr);
}
}
this.Deferred = function() {
return new Promise();
};
//回调执行方法
function _exec(arr) {
for (let i = 0, len = arr.length; i < len; i++) {
try {
arr[i] && arr[i]();
} catch (e) {
// console.warn("Error", e);
_exec(failArr);
}
}
};
// 监控异步方法参数
this.when = function(...args) {
//设置监控对象
dfd = args;
var i = args.length;
//向前遍历监控对象
for (--i; i >= 0; i--) {
//不存在监控对象 监控对象已经解决 监控对象失败
if (!args[i] || args[i].resolved || args[i].rejected || !args[i] instanceof Promise) {
args.splice(i, 1)
}
}
return this; // 返回等待者对象
};
//解决成功回调函数添加方法
this.done = function(...args) {
doneArr = doneArr.concat(args); // 向成功毁掉函数容器中添加回调方法
return this;
};
//解决失败回调函数添加方法
this.fail = function(...args) {
failArr = failArr.concat(args); // 向失败回调函数中添加方法
return this;
};
}
;(function(){
var waiter = new Waiter(); // 创建一个等待者实例
var first = function() {
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 1000);
return promise; // 返回监听这对象
}();
var second = function() { // 第二个对象
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 2000);
return promise;
}();
waiter.when(first, second).done(() => {
console.log("success");
}).fail(() => {
console.log("fail");
})
})();
;(function(){
var waiter = new Waiter(); // 创建一个等待者实例
var first = function() {
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 1000);
return promise; // 返回监听这对象
}();
var second = function() { // 第二个对象
var promise = waiter.Deferred();
setTimeout(() => {
promise.resolve();
}, 3000);
return promise;
}();
waiter.when(first, second).done(() => {
throw new Error("test");
}).fail(() => {
console.log("fail");
})
})();
Promise
Promise
就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败及其结果值,Promise
有各种开源实现,在ES6
中被统一规范,由浏览器直接支持。上面我们实现的等待者模式更类似于Promise.all()
。
示例
这个方法返回一个新的promise
对象,该promise
对象在iterable
参数对象里所有的promise
对象都成功的时候才会触发成功,一旦有任何一个iterable
里面的promise
对象失败则立即触发该promise
对象的失败。这个新的promise
对象在触发成功状态以后,会把一个包含iterable
里所有promise
返回值的数组作为成功回调的返回值,顺序跟iterable
的顺序保持一致;如果这个新的promise
对象触发了失败状态,它会把iterable
里第一个触发失败的promise
对象的错误信息作为它的失败错误信息。Promise.all
方法常被用于处理多个promise
对象的状态集合。
var p1 = new Promise((resolve, reject) => {
resolve("success1");
})
var p2 = new Promise((resolve, reject) => {
resolve("success2");
})
var p3 = new Promise((resolve, reject) => {
reject("fail");
})
Promise.all([p1, p2]).then((result) => {
console.log(result); // 成功状态 // ["success1", "success2"]
}).catch((error) => {
console.log(error);
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result);
}).catch((error) => {
console.log(error); // 失败状态 // fail
})
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://juejin.cn/post/6844903645855612942
https://segmentfault.com/a/1190000021413444
https://www.cnblogs.com/hsp-blog/p/5889842.html