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 儘量不要用在查找路徑比較深的節點,不然會增加它的時間複雜度,這裏我們可以採取存儲中間節點的辦法 來縮短它的路徑,用內存換性能。
當然如果一個節點下方的子節點太多,也會影響這些方法的使用性能。所以 我們在構建節點樹時,也要合理佈局。