• 性能最高的javascript 发布订阅系统(pub/sub)Arbiter.js 源码分析


    var Arbiter = (function () {
     var create_arbiter = function () {
      var subscriptions = {};// 订阅者
      var wildcard_subscriptions = {};// 通配符队列对象
      var persistent_messages = {};// 公共消息,除开特别指定(persist:false的)订阅者之外,所有订阅者都要接收此消息,即使是消息发布之后再订阅
      var id_lookup = {};// 订阅者队列以索引, 供:unsubscribe和resubscribe使用
      var new_id = 1;// id原子
      return {
       'version':'1.0'
       ,'updated_on':'2011-12-19'
       //创建一个全新的arbiter发布订阅系统
       ,'create': function() { return create_arbiter(); }
       //订阅
       ,'subscribe': function() {
        var msg, messages, subscription_list, persisted_subscription_list, subscription, func, options={}, context, wildcard=false, priority=0, id, return_ids=[];
        if (arguments.length<2) { return null; }
        messages = arguments[0];
        // Function is always last argument
        // 订阅者回调总是在最后一个参数
        func = arguments[arguments.length-1]; 
        // 订阅者参数
        if (arguments.length>2) { options = arguments[1] || {}; }
        // 订阅者上下文
        if (arguments.length>3) { context = arguments[2]; }
    
        // 权重,值越低,越在最早执行
        if (options.priority) {
         priority = options.priority;
        }
        //分解消息类型以(topic)
        if (typeof messages=="string") {
         messages = messages.split(/[,\s]+/);//","或空格分割字符串
        }
        for (var i=0; i<messages.length; i++) {
         msg = messages[i];
         // If the message ends in *, it's a wildcard subscription
         // 如果消息以*结尾,则认为这是一个通配符订阅
         if (/\*$/.test(msg)) {
          wildcard = true;
          msg = msg.replace(/\*$/,'');
          // 存入通配符订阅者队列
          subscription_list = wildcard_subscriptions[msg];    
          if (!subscription_list) {
           wildcard_subscriptions[msg] = subscription_list = [];
          }
         }
         else {
          // 存入订阅者队列
          subscription_list = subscriptions[msg];    
          if (!subscription_list) {
           subscriptions[msg] = subscription_list = [];
          }
         }
         // id索引自增
         id = new_id++;
         // 创建订阅者对象
         subscription = {'id':id,'f':func,p:priority,self:context,'options':options};
         // 存入订阅者索引对象
         id_lookup[id] = subscription;
         // 存入订阅者队列
         subscription_list.push ( subscription );
         // Sort the list by priority
         // 根据priority权利排序数组
         subscription_list = subscription_list.sort( function(a,b) {
          return (a.p>b.p?-1:a.p==b.p?0:1);
         } );
         // Put it back in after sorting
         // 将订阅者队列存入通配符队列对象或普通队列对象
         if (wildcard) {
          wildcard_subscriptions[msg] = subscription_list;
         }
         else {
          subscriptions[msg] = subscription_list;
         }
         // 将id存入“返回订阅者索引数组”
         return_ids.push(id);
         
         // Check to see if there are any persistent messages that need
         // to be fired immediately
         // 如果是参数中persist为假,并且公共消息中存在数据,则立执行订阅者回调函数,并传入对应的公共消息
         if (!options.persist && persistent_messages[msg]) {/// bug? !options.persist 我觉得应该为options.persist 
          persisted_subscription_list = persistent_messages[msg];
          for (var j=0; j<persisted_subscription_list.length; j++) {
           subscription.f.call( subscription.self, persisted_subscription_list[j], {persist:true} );
          }
         }
        }
        // Return an array of id's, or just 1
        // 返回一个id或者id数组,以供取消订阅时使用
        if (messages.length>0) {
         return return_ids;
        }
        return return_ids[0];
       }
       
       //发布消息
       ,'publish': function(msg, data, options) {
        var async_timeout=10,result,overall_result=true,cancelable=true,internal_data={},subscriber, wildcard_msg;
        // 通过消息类型得到订阅者列表
        var subscription_list = subscriptions[msg] || [];
        options = options || {};
        // Look through wildcard subscriptions to find any that apply
        // 循环通配符队列对象
        for (wildcard_msg in wildcard_subscriptions) {
         // 如果存在对应的消息类型,则将其加入订阅者列表
         if (msg.indexOf(wildcard_msg)==0) {
          subscription_list = subscription_list.concat( wildcard_subscriptions[wildcard_msg] );
         }
        }
    
        // 如果消息类型是公共消息
        if (options.persist===true) {
         // 将此消息存入公共消息队列
         if (!persistent_messages[msg]) {
          persistent_messages[msg] = [];
         }
         persistent_messages[msg].push( data );
        }
        // 如果没有订阅者,则直接返回
        if (subscription_list.length==0) { 
         return overall_result; 
        }
         // 判断此消息是否可被某个订阅者阻止
        if (typeof options.cancelable=="boolean") {
         cancelable = options.cancelable;
        }
        // 循环订阅者队列
        for (var i=0; i<subscription_list.length; i++) {
         subscriber = subscription_list[i];
         // 如果订阅者是unsubscribed状态,则跳过此订阅者继续处理下一个订阅者
         if (subscriber.unsubscribed) { 
          continue; // Ignore unsubscribed listeners
         }
         try {
          // Publisher OR subscriber may request async
          // 如果Publisher要求或者订阅者要求异步处理订阅者回调,则采用异步方式来处理订阅者回调
          if (options.async===true || (subscriber.options && subscriber.options.async)) {
           // 以setTimeout实现异步
           // async_timeout: 每一个订阅者回调递增延时一秒
           setTimeout( (function(inner_subscriber) {
            return function() {
             inner_subscriber.f.call( inner_subscriber.self, data, msg, internal_data );
            };
           })(subscriber), async_timeout++ );
          }
          else {
           // 如果允许订阅者取消事件传播,并且订阅者回调返回了false,则跳出循环,不再继续此消息传播
           result = subscriber.f.call( subscriber.self, data, msg, internal_data );
           if (cancelable && result===false) {
            break;
           }
          }
         }
         catch(e) {
          // 失败返回false
          overall_result = false;
         }
        }
        // 成功返回false
        return overall_result;
       }
       
       // 临时取消订阅
       ,'unsubscribe': function(id) {
        if (id_lookup[id]) {
          id_lookup[id].unsubscribed = true;
          return true;
        }
        return false;
       }
       
       // 回复订阅
       ,'resubscribe': function(id) {
        if (id_lookup[id]) {
          id_lookup[id].unsubscribed = false;
          return true;
        }
        return false;
       }
       
      };
     };
     return create_arbiter();
     
    })();
    能力有限,有错误之处请指正
    注:转载请注明出处:偷饭猫email: xiaodong1986@me.com
  • 相关阅读:
    MySQL 5.7笔记
    Golang学习笔记
    Ubuntu使用笔记
    Linux下安装nginx和php
    Eclipse远程调试Java程序
    CentOS下glibc更新
    Linux服务器运行环境搭建(三)——MySQL数据库安装
    Linux服务器运行环境搭建(二)——Redis数据库安装
    Linux下定时任务Crontab的使用
    Linux下nginx安装与配置
  • 原文地址:https://www.cnblogs.com/willian/p/2880477.html
Copyright © 2020-2023  润新知