博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
发布订阅管道化
阅读量:6590 次
发布时间:2019-06-24

本文共 3747 字,大约阅读时间需要 12 分钟。

发布订阅作为一种常见的设计模式,在前端模块化领域可以用来解决模块循环依赖问题。

看一个简单的示例

// 消息中间件v1 var msghub = (function() {  var listener = [];  return {      on: function(type, cb, option) {      listener[type] = listener[type] || [];      option = option || {};      listener[type].push({          cb: cb,          priority: option.priority || 0      });    },    fire: function(type, dataObj) {        if (listener[type]) {          listener[type].sort((a, b) => a.priority - b.priority).forEach((item) => {            item.cb.call(null, dataObj);        });      }    }  }})();

以及消息中间件的使用模块

// a.jsmsghub.on('data', function(data) {    console.log(data.val + 1); // 3})// b.jsmsghub.on('data', function(data) {    console.log(data.val + 2); // 4})// c.jsmsghub.fire('data', {    val: 2});

当c模块触发data事件的时候,a和b模块的监听函数都会被执行并输出相应的结果。

订阅函数管道化

上面的例子基本可以满足需求了,但是有时候我们希望多个订阅函数之间可以传递执行结果,类似linux管道a.pipe(b).pipe(c)…这种,上一个函数的输出是下一个函数的输入。针对这种管道化需求我们对msghub的回调遍历从forEach改为reduce方式,如下代码所示

// 消息中间件v2 支持执行结果传递var msghub = (function() {  var listener = [];  option = option || {};  return {      on: function(type, cb, option) {      listener[type] = listener[type] || [];      listener[type].push({          cb: cb,          priority: option.priority || 0      });    },    fire: function(type, dataObj) {        if (listener[type]) {          listener[type].sort((a, b) => b.priority - a.priority).reduce((pre, cur) => {            let result = cur.cb.call(null, pre) || pre; // 如果一个订阅函数没有返回值则传递上上个订阅函数的执行结果,如果需要完全的管道化的话就把|| pre去掉即可            return result;        }, dataObj);      }    }  }})();

测试一下上面的msghub

// a.jsmsghub.on('data', function(data) {    console.log('module a get num:' + data.val); // 3    return {      val: ++data.val    };})// b.jsmsghub.on('data', function(data) {  console.log('module b get num:' + data.val)  return {      val: data.val + 3  }})// d.jsmsghub.on('data', function(data) {  console.log('module d get num:' + data.val);})// e.jsmsghub.on('data', function(data) {  console.log('module e get num:' + data.val);})// c.jsmsghub.fire('data', {    val: 2});

使用改良后的msghub的话

// a.js    msghub.on('data', function(data) {        console.log('module a get num:' + data.val); // 3        return {          val: ++data.val        };    })    // b.js    msghub.on('data', function(data) {        console.log('module b get num:' + data.val)        return {            val: data.val + 3        }    })    // d.js    msghub.on('data', function(data) {      console.log('module d get num:' + data.val);    })    // e.js    msghub.on('data', function(data) {      console.log('module e get num:' + data.val);    })    // c.js    msghub.fire('data', {        val: 2    });

最终打印输出如下信息:

module a get num:2module b get num:3module d get num:6module e get num:6

订阅函数支持异步

上面的例子中有一个问题就是订阅函数必须是同步代码,如果a.js包含下述异步代码的话就会出问题

// a.jsmsghub.on('data', function(data) {  console.log('module a get num:' + data.val); // 3  return new Promise(function(resolve, reject) {    setTimeout(() => {      resolve({        val: ++data.val      })    }, 1000);  });})

针对可能同步可能异步的情况我们需要进一步改良msghub来支持,该请asyn和await出场了

// 消息中间件v3 支持异步管道化var msghub = (function() {  var listener = [];  return {    on: function(type, cb, option) {      listener[type] = listener[type] || [];      option = option || {};      listener[type].push({        cb: cb,        priority: option.priority || 0      });    },    fire: function(type, dataObj) {      if (listener[type]) {        let listenerArr = listener[type].sort((a, b) => b.priority - a.priority);        (async function iter() {          let val = dataObj;          for (const item of listenerArr) {            val = await item.cb.call(null, val);          }        })();      }    }  }})();

注意: 上述代码可以在node环境做测试,如果需要在浏览器中运行的话,需要对for of和async await进行babel编译

转载地址:http://lrkio.baihongyu.com/

你可能感兴趣的文章
Chalubo僵尸网络来袭 IOT设备或将受到DDoS攻击
查看>>
如何实现百万TPS?详解JMQ4的存储设计
查看>>
这么说吧,NIO很简单,其实就是个牛逼IO
查看>>
使用Python快速获取公众号文章定制电子书(二)
查看>>
iOS下JS与OC互相调用(七)--Cordova 基础
查看>>
Three.js 关于立方体贴图产生边缘锯齿问题
查看>>
Nacos v0.7.0:对接CMDB,实现基于标签的服务发现能力
查看>>
【开发问题记录①】关于滑动CollectionView时ContentSize变化的问题
查看>>
java中GC的基本概念
查看>>
building xxx gradle project info的解决办法
查看>>
Vagrant (一) - 基本知识
查看>>
在 CentOS 7 上搭建 Jenkins + Maven + Git 持续集成环境
查看>>
数据结构与算法 | Leetcode 19. Remove Nth Node From End of List
查看>>
一起来读you don't know javascript(一)
查看>>
[LeetCode] 862. Shortest Subarray with Sum at Least K
查看>>
【分享】终端命令工具 自动生成vue组件文件以及修改router.js
查看>>
[LeetCode] Student Attendance Record I
查看>>
PHP回顾之多进程编程
查看>>
spring boot + redis
查看>>
Ajax技术细节
查看>>