/* CallbacksInvoker 用来根据 Key 管理并调用回调方法。*/
/* platform下的js文件 */
const js = require('./js');
/* js.array是一个对象。里面有很多方法,比如fastRemoveAt */
const fastRemoveAt = js.array.fastRemoveAt;
function empty() { }
/* 定义一个 CallbackInfo 的function */
function CallbackInfo() {
/* callback: 回调函数 初始化为一个空的function */
this.callback = empty;
this.target = undefined;
/* 是否一次 */
this.once = false;
}
/* 添加set方法 */
CallbackInfo.prototype.set = function (callback, target, once) {
/* 设置回调函数,设置执行的nodetarget,设置是否是once, */
this.callback = callback;
this.target = target;
this.once = !!once;//强转为bool值
};
/* 创建对象池对象,内置的_pool 数组长度为32 */
let callbackInfoPool = new js.Pool(function (info) {
info.callback = empty;
info.target = undefined;
info.once = false;
return true;
}, 32);
/* 设置对象池对象的get方法 */
callbackInfoPool.get = function () {
return this._get() || new CallbackInfo();
};
/* 声明fuction CallbackList 内置几个属性*/
function CallbackList() {
this.callbackInfos = [];
this.isInvoking = false;//是否正在触发
this.containCanceled = false;//是否包含取消,假如整个list存在过一次,则需要记录,需要清理array
}
/* CallbackList函数的原型对象 */
let proto = CallbackList.prototype;
/**
* !#zh
* 从列表中移除与指定目标相同回调函数的事件。
* @param cb
*/
proto.removeByCallback = function (cb) {
/* 遍历存储的所有的info,根据回调函数判断是否相等,相等的话,回收info */
for (let i = 0; i < this.callbackInfos.length; ++i) {
let info = this.callbackInfos[i];
if (info && info.callback === cb) {
/* Pool.prototype.put = function (obj) 调用put函数,实现回收info,提效,不销毁 */
callbackInfoPool.put(info);
/* 快速移除 list数组内 的这个 item*/
fastRemoveAt(this.callbackInfos, i);
--i;
}
}
};
/**
* !#zh
* 从列表中移除与指定目标相同调用者的事件。
* @param target
*/
proto.removeByTarget = function (target) {
/* 遍历,根据target,进行移除 */
for (let i = 0; i < this.callbackInfos.length; ++i) {
const info = this.callbackInfos[i];
if (info && info.target === target) {
callbackInfoPool.put(info);
fastRemoveAt(this.callbackInfos, i);
--i;
}
}
};
/**
* !#zh
* 移除指定编号事件。
*
* @param index
*/
proto.cancel = function (index) {
const info = this.callbackInfos[index];
if (info) {
callbackInfoPool.put(info);
/* 直接将容器内index对应的info置为空 */
this.callbackInfos[index] = null;
}
this.containCanceled = true;
};
/**
* !#zh
* 注销所有事件。
*/
proto.cancelAll = function () {
for (let i = 0; i < this.callbackInfos.length; i++) {
const info = this.callbackInfos[i];
if (info) {
/* 回收info,并且把容器内index对应的内容置为空 */
callbackInfoPool.put(info);
/* iteminfo置为空 */
this.callbackInfos[i] = null;
}
}
this.containCanceled = true;
};
// filter all removed callbacks and compact array
// 过滤所有已删除的回调和紧凑数组
proto.purgeCanceled = function () {
for (let i = this.callbackInfos.length - 1; i >= 0; --i) {
const info = this.callbackInfos[i];
if (!info) {
/* 把为空的item,对应的index内容删除,缩减array */
fastRemoveAt(this.callbackInfos, i);
}
}
this.containCanceled = false;
};
/* 清理所有注册的事件 */
proto.clear = function () {
this.cancelAll();
this.callbackInfos.length = 0;
this.isInvoking = false;
this.containCanceled = false;
};
const MAX_SIZE = 16;
/* 长度固定的对象缓存池,可以用来缓存各种对象类型。*/
let callbackListPool = new js.Pool(function (info) {
info.callbackInfos = [];
info.isInvoking = false;
info.containCanceled = false;
return true;
}, MAX_SIZE);
callbackListPool.get = function () {
return this._get() || new CallbackList();
};
/**
* !#en The callbacks invoker to handle and invoke callbacks by key.
* !#zh CallbacksInvoker 用来根据 Key 管理并调用回调方法。
* @class CallbacksInvoker
*/
function CallbacksInvoker() {
/* 创建一个类map容器 */
this._callbackTable = js.createMap(true);
}
/* proto 作为 CallbacksInvoker的原型 */
proto = CallbacksInvoker.prototype;
/**
* !#zh
* 事件添加管理
*
* @param key
* @param callback
* @param target
* @param once
*/
proto.on = function (key, callback, target, once) {
/* 从map获取key对应的list */
let list = this._callbackTable[key];
/* list不存在 创建一个list*/
if (!list) {
list = this._callbackTable[key] = callbackListPool.get();
}
/* 设置info,核心,把key 回调 target once参数传进去 */
let info = callbackInfoPool.get();
info.set(callback, target, once);
list.callbackInfos.push(info);
};
/**
*
* !#zh
* 检查指定事件是否已注册回调。
*
* !#en
* Check if the specified key has any registered callback. If a callback is also specified,
* it will only return true if the callback is registered.
*
* @method hasEventListener
* @param {String} key
* @param {Function} [callback]
* @param {Object} [target]
* @return {Boolean}
*/
/* 检测这个key是否注册了 */
proto.hasEventListener = function (key, callback, target) {
const list = this._callbackTable[key];
if (!list) {
return false;
}
// check any valid callback
const infos = list.callbackInfos;
if (!callback) {
// Make sure no cancelled callbacks
/* // 确保没有取消的回调 */
if (list.isInvoking) {/* 假如正在执行 */
for (let i = 0; i < infos.length; ++i) {
if (infos[i]) {//只要存在一个,就返回true
return true;
}
}
return false;
}
else {
return infos.length > 0;
}
}
/* 需要校验callback参数的时候 ,判断cb 和 target也要一样*/
for (let i = 0; i < infos.length; ++i) {
const info = infos[i];
if (info && info.callback === callback && info.target === target) {
return true;
}
}
return false;
};
/**
* !#zh
* 移除在特定事件类型中注册的所有回调或在某个目标中注册的所有回调。
*
* !#en
* Removes all callbacks registered in a certain event type or all callbacks registered with a certain target
* @method removeAll
* @param {String|Object} keyOrTarget - The event key to be removed or the target to be removed
*/
proto.removeAll = function (keyOrTarget) {
if (typeof keyOrTarget === 'string') {
// remove by key
/* 根据key删除 */
const list = this._callbackTable[keyOrTarget];
if (list) {
if (list.isInvoking) {
/* * 注销所有事件。*/
list.cancelAll();
}
else {
/* /* 清理所有注册的事件 */ * /
list.clear();
/* 回收list */
callbackListPool.put(list);
delete this._callbackTable[keyOrTarget];
}
}
}
else if (keyOrTarget) {
// remove by target
/* 假如传参 是target,进行list里面的target比较 */
for (const key in this._callbackTable) {
const list = this._callbackTable[key];
/* 正在emit的时候 */
if (list.isInvoking) {
const infos = list.callbackInfos;
for (let i = 0; i < infos.length; ++i) {
const info = infos[i];
/* 判断target是否相等 */
if (info && info.target === keyOrTarget) {
/* 根据target,进行cancel */
list.cancel(i);
}
}
}
else {
list.removeByTarget(keyOrTarget);
}
}
}
};
/**
* !#zh
* 删除之前与同类型,回调,目标注册的回调。
*
* @method off
* @param {String} key
* @param {Function} callback
* @param {Object} [target]
*/
proto.off = function (key, callback, target) {
const list = this._callbackTable[key];
if (list) {
const infos = list.callbackInfos;
for (let i = 0; i < infos.length; ++i) {
const info = infos[i];
if (info && info.callback === callback && info.target === target) {
/* 正在emit的时候,移除置顶index的事件 */
if (list.isInvoking) {
list.cancel(i);//回收,置为null
}
else {
/* 回收、移除 */
fastRemoveAt(infos, i);
callbackInfoPool.put(info);
}
break;
}
}
}
};
/**
* !#en
* Trigger an event directly with the event name and necessary arguments.
* !#zh
* 通过事件名发送自定义事件
*
* @method emit
* @param {String} key - event type
* @param {*} [arg1] - First argument
* @param {*} [arg2] - Second argument
* @param {*} [arg3] - Third argument
* @param {*} [arg4] - Fourth argument
* @param {*} [arg5] - Fifth argument
* @example
*
* eventTarget.emit('fire', event);
* eventTarget.emit('fire', message, emitter);
*/
proto.emit = function (key, arg1, arg2, arg3, arg4, arg5) {
const list = this._callbackTable[key];
if (list) {
/* 当第一次执行某个key的emit的时候,rootInvoker = true
*/
const rootInvoker = !list.isInvoking;
list.isInvoking = true;
const infos = list.callbackInfos;
for (let i = 0, len = infos.length; i < len; ++i) {
const info = infos[i];
if (info) {
let target = info.target;
let callback = info.callback;
if (info.once) {/* 只需要执行一次,把注册干掉 */
this.off(key, callback, target);
}
/* 存在target的时候,执行target的callback */
if (target) {
callback.call(target, arg1, arg2, arg3, arg4, arg5);
}//否则,cb直接执行
else {
callback(arg1, arg2, arg3, arg4, arg5);
}
}
}
if (rootInvoker) {
list.isInvoking = false;//重置参数为false
if (list.containCanceled) {/* 包括了取消操作的时候,要处理array内容和大小 */
list.purgeCanceled();
}
}
}
};
if (CC_TEST) {
cc._Test.CallbacksInvoker = CallbacksInvoker;
}
/* 导出CallbacksInvoker */
module.exports = CallbacksInvoker;
CocosCreator 源码callbacks-invoker.js详解
最新推荐文章于 2024-09-21 09:29:16 发布