等待者模式

等待者模式

等待者模式是通过对多个异步任务进行监听,当异步任务完成后触发未来发生的动作,在没有Promise这个模型的时候,其实就已经出现这样类似的技术方案,不同的只是没有定制为一个技术规范,等待者模式不属于一般定义的23种设计模式的范畴,而通常将其看作广义上的技巧型设计模式。

描述#

等待者模式就是通过对异步进程监听,来触发未来发生的动作,举个例子当异步进程操作A、B需要都完成以后才能进行C进程操作,在开发中经常会这样,需要等到上个操作完成或者知道上个操作完成才去触发下个操作,而JavaScript又是单线程的,不能采用阻塞的方式去处理,在Promise规范出现之前通常都是使用回调的方式实现,这样很容易造成回调地狱,等待者模式就是在Promise规范制定之前一个类似于Promise的解决方案,可以算是Promise规范的一个参考前身。

实现#

Copy
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对象的状态集合。

Copy
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 })

每日一题#

Copy
https://github.com/WindrunnerMax/EveryDay

参考#

Copy
https://juejin.cn/post/6844903645855612942 https://segmentfault.com/a/1190000021413444 https://www.cnblogs.com/hsp-blog/p/5889842.html
posted @   WindRunnerMax  阅读(107)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
CONTENTS