cc.find 和getChildByName 都可以获取子节点
# 今天我们来探究一下这三个方法的效率
首先我们先阅读一下官方文档中cc.find、getChildByName和
getChildByUuid这三个方法有关的知识。
在官方文档中给出的find API描述是这样的。
Finds a node by hierarchy path, the path is case-sensitive. It will traverse the hierarchy by splitting the path using ‘/’ character. This function will still returns the node even if it is inactive. It is recommended to not use this function every frame instead cache the result at startup.
翻译过来是:
通过一个具有层次的且大小写敏感的路径来查找一个节点。它将通过使用‘/’字符分割路径来遍历层次结构。甚至这个节点是未激活的,这个方法也可以将它获取并返回。启动时每一帧都要写入缓存,建议不要在这个时候使用该方法。
在官方文档中给出的getChildByName 、getChildByUuid API描述就不贴了 很简单。
因为引擎的开源,我们似乎可以看到,每个接口的具体实现,现在我们来研究一下。
在位于cocos-creator/engine/cocos2d/core/utils/find.js 中:
// cc.find
@method find
* @static
* @param {String} path
* @param {Node} [referenceNode]
* @return {Node|null} the node or null if not found
*/
cc.find = module.exports = function (path, referenceNode) {
if (path == null) {//判断路径是否为空
cc.errorID(5600);
return null;
}
if (!referenceNode) {//判断参考节点是否为空
var scene = cc.director.getScene();//获取当前场景
if (!scene) {
if (CC_DEV) {
cc.warnID(5601);
}
return null;
}
else if (CC_DEV && !scene.isValid) {//判断该场景是否未被destory
cc.warnID(5602);
return null;
}
referenceNode = scene;
}
else if (CC_DEV && !referenceNode.isValid) {
cc.warnID(5603);
return null;
}
var match = referenceNode;
var startIndex = (path[0] !== '/') ? 0 : 1; // skip first '/'
var nameList = path.split('/');
// parse path //循环嵌套
for (var n = startIndex; n < nameList.length; n++) {
var name = nameList[n];
var children = match._children;
match = null;
for (var t = 0, len = children.length; t < len; ++t) {
var subChild = children[t];
if (subChild.name === name) {
match = subChild;
break;
}
}
if (!match) {
return null;
}
}
return match;
};
在位于cocos-creator/engine/cocos2d/core/utils/base-node.js 中:
/**
* !#en Returns a child from the container given its name.
* !#zh 通过名称获取节点的子节点。
* @method getChildByName
* @param {String} name - A name to find the child node.
* @return {Node} a CCNode object whose name equals to the input parameter
* @example
* var child = node.getChildByName("Test Node");
*/
getChildByName (name) {
if (!name) {
cc.log("Invalid name");
return null;
}
var locChildren = this._children;
for (var i = 0, len = locChildren.length; i < len; i++) {
if (locChildren[i]._name === name)
return locChildren[i];
}
return null;
},
/**
* !#en Returns a child from the container given its uuid.
* !#zh 通过 uuid 获取节点的子节点。
* @method getChildByUuid
* @param {String} uuid - The uuid to find the child node.
* @return {Node} a Node whose uuid equals to the input parameter
* @example
* var child = node.getChildByUuid(uuid);
*/
getChildByUuid (uuid) {
if (!uuid) {
cc.log("Invalid uuid");
return null;
}
var locChildren = this._children;
for (var i = 0, len = locChildren.length; i < len; i++) {
if (locChildren[i]._id === uuid)
return locChildren[i];
}
return null;
},
这么一看,在相同情况下都只取下一级的子节点。后两者的运算量要小于前者。
其实总的来看 ,cc.find 尽量不要用在查找路径比较深的节点,不然会增加它的时间复杂度,这里我们可以采取存储中间节点的办法 来缩短它的路径,用内存换性能。
当然如果一个节点下方的子节点太多,也会影响这些方法的使用性能。所以 我们在构建节点树时,也要合理布局。