cocos cc.find和getChildByName getChildByUuid三個接口的剖析比較

cc.find 和getChildByName 都可以獲取子節點

# 今天我們來探究一下這三個方法的效率

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章