events.js 源码分析

events.js 源码分析

1. 初始化
// 使用
this.ee = new EventEmitter();
// 源码
// 绑定this域,初始化 _events,_eventsCount和_maxListeners对象
function EventEmitter() {
  EventEmitter.init.call(this);
}
EventEmitter.init = function() {
  if (
    this._events === undefined ||
    this._events === Object.getPrototypeOf(this)._events
  ) {
    this._events = Object.create(null);
    this._eventsCount = 0;
  }

  this._maxListeners = this._maxListeners || undefined;
};
2.注册监听事件
// 使用
this.ee.on("message", function(text) {
  console.log(text);
  that.setState({
    text: text
  });
});
// 调用的是addListener
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.addListener = function addListener(type, listener) {
  // 注意最后一个参数为false
  return _addListener(this, type, listener, false);
};
function _addListener(target, type, listener, prepend) {
  var m;
  var events;
  var existing;
  // 判断是否是方法
  if (typeof listener !== "function") {
    throw ...
  }
	
  // this._events为单个EventEmitter对象中,注册事件的总对象,例如:{login:funcation(){xxxx},loginOut:funcation(){}}
  events = target._events;
  if (events === undefined) {
    events = target._events = Object.create(null);
    target._eventsCount = 0;
  } else {
    // To avoid recursion in the case that type === "newListener"! Before
    // adding it to the listeners, first emit "newListener".
    // 在添加监听时,判断是否有注册type='newListener'的监听,有的话,每_addListener便调用
    // newListener
    if (events.newListener !== undefined) {
      target.emit(
        "newListener",
        type,
        listener.listener ? listener.listener : listener
      );

      // Re-assign `events` because a newListener handler could have caused the
      // this._events to be assigned to a new object
      events = target._events;
    }
    // 获取是否已经注册过了
    existing = events[type];
  }

  if (existing === undefined) {
    // Optimize the case of one listener. Don't need the extra array object.
    // 没有注册过,赋值
    existing = events[type] = listener;
    ++target._eventsCount;
  } else {
    if (typeof existing === "function") {
      // Adding the second element, need to change to array.
      // 如果有相同的type,则将 新,旧listener封装成数组,并且根据prepend
      // 决定先后执行顺序
      existing = events[type] = prepend
        ? [listener, existing]
        : [existing, listener];
      // If we've already got an array, just append.
    } else if (prepend) {
      existing.unshift(listener);
    } else {
      existing.push(listener);
    }

    // Check for listener leak
    // 检查listener是否超过最大值,m初始化为10
    m = $getMaxListeners(target);
    if (m > 0 && existing.length > m && !existing.warned) {
      ...
    }
  }
  return target;
}

  1. 获取EventEmitter对象events = target._events;

  2. events == null 进行判断

    1. true: 初始化 events = target._events = Object.create(null); target._eventsCount = 0;
    2. false:
      1. 判断是否存在newListener
        1. 存在: 调用target.emit("newListener",xxxx)
      2. existing = events[type];获取缓存数据,没有为undefined
  3. 判断existing === undefined

    1. true: 赋值existing = events[type] = listener; ++target._eventsCount;

      相当于给EventEmitter赋值{xxxx,'type':listener}

    2. false: 意味着注册了相同的type,将会生成{xxxx,'type':[listener1,listener2]}

      类似对象.ps: prepend == true 的时候,新listener,将会排列在数组的最前面.

  4. 检查listener是否超过最大值,初始化为10

  5. 返回target也就是当前EventEmitter对象.

3.发送事件
// 使用
this.ee.emit("message", "hello world 按钮1");
EventEmitter.prototype.emit = function emit(type) {
  var args = [];
  // 获取除了type之外的参数,也就是传递参数
  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
  var doError = type === "error";
	// this._events为单个EventEmitter对象中,注册事件的总对象,例如:{login:funcation(){xxxx},loginOut:funcation(){}}
  var events = this._events;
  
  // 进行error判断 暂时不关注
  ... 
  // 获取到type对应的执行函数listener
  var handler = events[type];
	// 没有执行函数 return
  if (handler === undefined) return false;
	
  // 根据是funcation还是数组,分别执行对应的调用函数方法
  if (typeof handler === "function") {
    ReflectApply(handler, this, args);
  } else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args);
  }
  return true;
};
// 兼容处理
var ReflectApply =
  R && typeof R.apply === "function"
    ? R.apply
    : function ReflectApply(target, receiver, args) {
        return Function.prototype.apply.call(target, receiver, args);
      };
  1. 通过arguments获取到除type外其他的传入参数,用于最后调用方法时传递给执行函数
  2. 错误处理
  3. 获取到handler,并判断是否为undefined
  4. 根据获取到的handler,判断是funcation还是数组,分别执行对应的调用函数方法.
4.once解析
// 使用 
// 注册
this.ee.once("message3", function(text) {
  alert(text);
});
// 发送
this.ee.emit("message3", "按钮3,只调用一次this.ee.once");
EventEmitter.prototype.once = function once(type, listener) {
  if (typeof listener !== "function") {
    throw ....
  }
  // 包装 listener
  this.on(type, _onceWrap(this, type, listener));
  return this;
};

function _onceWrap(target, type, listener) {
  var state = {
    fired: false,
    wrapFn: undefined,
    target: target,
    type: type,
    listener: listener
  };
  // 将onceWrapper的this绑定为上面创建的state对象
  var wrapped = onceWrapper.bind(state);
  wrapped.listener = listener;
  state.wrapFn = wrapped;
  return wrapped;
}
function onceWrapper() {
  var args = [];
  for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
  if (!this.fired) {
    // 判断是否使用过,没使用过的话先删除type--onceWrapper
    this.target.removeListener(this.type, this.wrapFn);
    this.fired = true;
    // 执行listener,并且传递数据
    ReflectApply(this.listener, this.target, args);
  }
}
  1. 包装执行函数listener

  2. 创建state对象,将onceWrapperthis绑定为state

  3. 调用发送事件emit后调用到onceWrapper方法,先删除EventEmitter对应的type:onceWrapper,

    然后执行state中的listener

  4. 再次发送事件则在EventEmitter找不到对应的type,实现了只能监听一次.

posted @ 2019-08-07 16:01  被咯苏州  阅读(143)  评论(0编辑  收藏  举报