前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >等待者模式

等待者模式

作者头像
WindrunnerMax
发布2020-12-31 11:05:46
1.2K0
发布2020-12-31 11:05:46
举报
文章被收录于专栏:Czy‘s BlogCzy‘s Blog

等待者模式

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

描述

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

实现

代码语言:javascript
复制
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对象的状态集合。

代码语言:javascript
复制
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
})

每日一题

代码语言:javascript
复制
https://github.com/WindrunnerMax/EveryDay

参考

代码语言:javascript
复制
https://juejin.cn/post/6844903645855612942
https://segmentfault.com/a/1190000021413444
https://www.cnblogs.com/hsp-blog/p/5889842.html
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 等待者模式
    • 描述
      • 实现
    • Promise
      • 示例
    • 每日一题
      • 参考
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档