UI和代碼結合的弊端
1.大量通過界面引用UI節點
如下圖所示,通過腳本元件大量直接引用UI節點,會在相應的描述檔案中記錄相應的key和value,在一定程度上會增加相關描述檔案的大小,進而影響這個描述檔案加載所花費的時間。進一步影響資源加載總時間。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcsQXYtJ3bm9CXldWYtlWPzNXZj9mcw1ycz9WL49jb1c0Y1tmaNJTUq5ENnpmTxUkaNBTVqlldrRUT1UERNlHOTp1cs1mWrZkMiNnQYRmdR5mYsJlbiZnTywEd5ITW1d2Ri9GcYl1M1kHZzQ2MMZ3bENGMShUYvwlbj5yZtlmbkN3YuQnclZnbvN2Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)
{
"__type__": "85d24iUBchG45eRtzPrngjE",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"label": {
"__id__": 7
},
"node1": {
"__id__": 9
},
"node2": {
"__id__": 12
},
"_id": ""}
通過腳本元件大量直接引用UI節點這種方式還有一個弊端,當節點上的腳本元件因某種原因丢失或者說被重置了,那麼還需要被重新挂載一次,如果時間長了,可能都忘記了誰對應的誰。
2.代碼中大量查找節點
第一種方式,代碼中通過 getChildByName, getChildByUuid 函數查到相應的節點, 在此以 getChildByName 函數來舉例。通過下面代碼可以看出,正序周遊查找相應節點的名字,傳回第一個查到的節點。
/**
* !#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;
}
舉個例子:如下所示,一個根節點下依次有節點A,節點B,節點C,節點D 四個子節點。現在通過 getChildByName 來擷取 節點D。
--根節點
----子節點A
----子節點B
----子節點C
----子節點D
如果現在需要查找子節點A呢:
第一次周遊: 查找子節點A,滿足條件,則傳回子節點A
也就是說 getChildByName 查找子節點A的時間複雜度為1。
如果現在需要查找子節點D呢:
第一次周遊: 查找子節點A,不滿足條件,則繼續周遊查找
第二次周遊: 查找子節點B,不滿足條件,則繼續周遊查找
第三次周遊: 查找子節點C,不滿足條件,則繼續周遊查找
第四次周遊: 查找子節點D,不滿足條件,則傳回子節點D
也就是說 getChildByName 查找子節點A的時間複雜度為4。
綜上所述: getChildByName 查找相應的節點的時間複雜度為 N。意味得查找的節點廣度大,所需要的時間越長。代碼中大量通過 getChildByName , getChildByUuid 函數查到相應的節點是一個影響性能的因子。
第二種方式,代碼中通過 cc.find 函數查到相應的節點,從下面代碼可以看出,兩層正序周遊查找相應的節點。第一層正序周遊的因子是傳入的路徑分割。第二層正序周遊的因子是節點的children。
/**
* 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.
*
* @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) {
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;
};
舉個例子:如下所示,現在一個場景上的節點關系如下。
-- 場景根節點
---- 子節點A
----- 子節點A1
--- 子節點B
--- 子節點C
----- 子節點C1
--- 子節點D
----- 子節點D1
----- 子節點D2
如果現在需要查找子節點A1呢(暫不考慮第二個參數的情況下):
cc.find('子節點A/子節點A1') 開始周遊是 names = [子節點A,子節點A1]
第一層第一次周遊: 找到子節點A,滿足條件,則進行第二層周遊。
第二層第一次周遊: 找到子節點A1,滿足條件,則傳回。
也就是說 cc.find 查找子節點A1 的時間複雜度為2。
如果現在需要查找子節點D2呢(暫不考慮第二個參數的情況下):
cc.find(‘子節點D/子節點D2’) 開始周遊是 names = [子節點D,子節點D2]
第一層第一次周遊: 找到子節點A,不滿足條件,則繼續周遊。
第一層第一次周遊: 找到子節點B,不滿足條件,則繼續周遊。
第一層第一次周遊: 找到子節點C,不滿足條件,則繼續周遊。
第一層第一次周遊: 找到子節點D,滿足條件,則進行第二層周遊。
第二層第一次周遊: 找到子節點D1,不滿足條件,則繼續。
第二層第一次周遊: 找到子節點D2,滿足條件,則傳回。
也就是說 cc.find 查找子節點D2的時間複雜度為6
綜上所述: cc.find 查找一次節點的時間複雜度為 C(2 n)=n*(n-1)/(2*1)。意味着查找的節點廣度越大和深度越深所需要的時間越長。代碼中大量通過 cc.find 函數查到相應的節點是一個影響性能的因子。
無論是第一種方式還是第二種方式在代碼中引用相關的節點,如果由于某種原因,修改了節點之間的關系,進而查不到相應的節點引發的錯誤。還需要重新修改查找相應節點的路徑。
3. 大量通過界面引用UI節點 和 代碼中大量查找節點
通過這種方式來查找節點,同時具有上面兩種方法的弊端。更重要的是同時通過界面引用UI節點和代碼中查找UI節點,是不是感覺有點亂。