js发布订阅

122 阅读1分钟

Map实现

位操作符号>>>

// mitt 
// 源码地址:https://github.com/developit/mitt
export default function mitt(all) {
    all = all || new Map();
    
    return  {
        all,
        on (type, handler) {
            // 查找 map中是否有这个key
            const handlers = all.get(type);
            // 存在就直接push
            if (handlers) {
		handlers.push(handler);
	    } else {
                // 不存在就创建 value是一个数组
		all.set(type, [handler]);
	    }
        },
        off (type, handler) {
            const handlers = all.get(type);
            if (handlers) {
                if (handler) {
                    // 删除指定的 handler处理函数, 找到了 idx >>> 0 就是idx对应的索引
                    // 没找到 -1 变为 4294967295,原数组不会改变
                    handlers.splice(handlers.indexOf(handler) >>> 0, 1);
                } else {
                    // 如果没有传对应的handler,则把此type的全部事件全部清除
                    all.set(type, [])
                }
             }
        },
        emit (type, evt) {
            let handlers = all.get(type);
            if (handlers) {
                handlers.slice().map((handler) => {
                    handler(evt);
                })
            }
            // 如果存在监听*的情况,则会将事件全部触发一次
            handlers = all.get('*');
            if (handlers) { 
                handlers.slice().map((handler) => { 
                    handler(type, evt); 
                }); 
             }
        }
    }
}

类实现

  • 支持链式调用
  • 支持自定义this
  • once实现:执行监听方法后 执行off删除监听事件
//tiny-emitter
// 源码地址:https://github.com/scottcorgan/tiny-emitter
function E () {
	// Keep this empty so it's easier to inherit from
	// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
  }
  
  E.prototype = {
	on: function (name, callback, ctx) {
	  var e = this.e || (this.e = {});
  
	  (e[name] || (e[name] = [])).push({
		fn: callback,
		ctx: ctx
	  });
  
	  return this;
	},
  
	once: function (name, callback, ctx) {
	  var self = this;
	  function listener () {
		self.off(name, listener);
		callback.apply(ctx, arguments);
	  };
  
	  listener._ = callback
	  return this.on(name, listener, ctx);
	},
  
	emit: function (name) {
	  var data = [].slice.call(arguments, 1);
	  var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
	  var i = 0;
	  var len = evtArr.length;
  
	  for (i; i < len; i++) {
		evtArr[i].fn.apply(evtArr[i].ctx, data);
	  }
  
	  return this;
	},
  
	off: function (name, callback) {
	  var e = this.e || (this.e = {});
	  var evts = e[name];
	  var liveEvents = [];
  
	  if (evts && callback) {
		for (var i = 0, len = evts.length; i < len; i++) {
		  if (evts[i].fn !== callback && evts[i].fn._ !== callback)
			liveEvents.push(evts[i]);
		}
	  }
  
	  // Remove event from queue to prevent memory leak
	  // Suggested by https://github.com/lazd
	  // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
  
	  (liveEvents.length)
		? e[name] = liveEvents
		: delete e[name];
  
	  return this;
	}
  };
  
  module.exports = E;
  module.exports.TinyEmitter = E;