性能最高的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
posted @ 2013-01-28 20:24  池中物王二狗  阅读(700)  评论(0编辑  收藏  举报
转载入注明博客园 王二狗Sheldon Email: willian12345@126.com https://github.com/willian12345