如何优化RadComboBox的clearItems函数

时间:2017-10-20 21:15:35

标签: javascript jquery telerik telerik-combobox

我有一个MultiSelectDropDown,也就是说,多个RadComboBox控件以组合方式使用。例如,我可以为区域提供下拉列表,为仓库提供另一个下拉列表,为用户提供另一个下拉列表。这个想法是在更高级别选择或取消选择项目时动态更改较低级别的内容。问题是,在选择了很多项目的情况下,由于某些Telerik functions,这变得非常慢,但我不明白为什么。这是来自MultiSelectDropDown原型的客户端的一块:

changeLowerLevels: function (valueIndex, values, value) {
    if (!this.canChange) return;
    //Get selected values from combobox
    var combo = $find(this.ddlIDs[valueIndex - 1]);
    var cbItems = combo.get_checkedItems();
    var selectedItems = [];
    var change = null;
    var counter = 0;
    if (cbItems.length) this.filterString = "";
    for (var i = 0; i < cbItems.length; i++) {
        counter++;
        if (this.filterString == "") this.filterString = cbItems[i].get_text();
        selectedItems.push(cbItems[i].get_value());
    }
    if (counter > 1) this.filterString += " with " + (counter - 1) + " other" + ((counter > 2) ? "s" : "");
    if (JSON.stringify(selectedItems) === JSON.stringify(this.selectedItems[valueIndex - 1]) || selectedItems == [])
        return;
    this.selectedItems[valueIndex - 1] = selectedItems;

    var controlObject = this;
    var combo = $find(this.ddlIDs[valueIndex]);
    var comboItems = combo.get_items();
    if(!this.disabled) combo.enable();
    combo.clearItems();

    if (valueIndex == 1) this.twoLevelCache = values;
    var val = values;

    //break if all items are found
    var nrOfSelectedItems = this.selectedItems[valueIndex - 1].length;
    var nrOfFoundItems = 0;
    var index = 0;
    var indexes = [];
    var found = false;
    while (nrOfFoundItems < nrOfSelectedItems && val[index] !== undefined) {
        found = (this.selectedItems[valueIndex - 1].indexOf(val[index].Value) != -1);
        if (!(found))
            index++;
        else {
            indexes.push(index)
            nrOfFoundItems++;
            index++;
        }
    }

    //separators from valuesIndex - 1 level
    var controlObject = this;
    for (var i = 0; i < indexes.length; i++) {
        var separator = new Telerik.Web.UI.RadComboBoxItem();
        separator.set_text("<span><a class=\"checkAll tt-multi-uncheck-icon\" index=\"" + index + "\">U</a>" + $find(this.ddlIDs[valueIndex - 1]).findItemByValue(val[indexes[i]].Value).get_text() + "</span>");
        separator.set_value("");
        separator.set_isSeparator(true);
        comboItems.add(separator);
        this.twoLevelCache.push(val[indexes[i]].Levels);

        //valuesIndex level
        var valuesArray = val;
        var comboItem = new Telerik.Web.UI.RadComboBoxItem();
        for (var depot in valuesArray[indexes[i]].Levels) {
            comboItem = new Telerik.Web.UI.RadComboBoxItem();
            comboItem.set_text(valuesArray[indexes[i]].Levels[depot].Name);
            comboItem.set_value(valuesArray[indexes[i]].Levels[depot].Value);
            comboItems.add(comboItem);
            comboItem = null;
        }

        $('#' + this.ddlIDs[valueIndex] + '_DropDown a.checkAll').unbind().on("click", function () {
            checkAllLowerItems(this, controlObject.ddlIDs[valueIndex]);
        });
    }
    combo.set_emptyMessage(this.allText);
    //$("#" + this.ddlIDs[valueIndex]).html(returnValue);
    if (this.ddlIDs.length > valueIndex + 1) {
        var paramToPass = (((val == undefined) || (val[index] === undefined)) ? ("") : (val[index]));
        if (this.allText.length > 0)
            this.changeLowerLevels(valueIndex + 1, paramToPass, "");
        else {
            if (paramToPass !== "")
                paramToPass = paramToPass.Levels;
            if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
                this.changeLowerLevels(valueIndex + 1, paramToPass, "");
            }
            else {
                this.changeLowerLevels(valueIndex + 1, paramToPass, val[index].Levels[0].Value);
            }
        }
    }
    else {
        if (this.allText.length > 0)
            this.selectedItems[valueIndex] = "";
        else
            if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
                this.selectedItems[valueIndex] = "";
            }
            else {
                this.selectedItems[valueIndex] = val[index].Levels[0].Value;
            }
    }

    this.setText();
}

combo.clearItems()极其缓慢。我已经看看它是如何实现的:

function (){var f=this._parent._getControl();?if(f._checkBoxes){f._checkedIndicesJson="[]";?f._checkedIndices=[];?var g=f.get_items();?for(var d=0,e=g.get_count();?d<e;?d++){var c=f.get_items().getItem(d);?c.set_checked(false);?}f.updateClientState();?}a.RadComboBoxItemCollection.callBaseMethod(this,"clear");?}

如何确保此Javascript功能加速?

1 个答案:

答案 0 :(得分:1)

我终于通过重写Telerik客户端功能解决了这个问题。这是一个漫长而艰难的调试,但它在最困难的情况下产生了很大的性能提升。从~30 000毫秒到~300。让我们看看优化的部分:

  1. 实际重写
  2. /* Overriding Telerik functions Start */ var overridenTelerikControls = false; function overrideTelerikFunctionalities() { if (!overridenTelerikControls) { overridenTelerikControls = true; Telerik.Web.UI.RadComboBox.prototype.clearItems = function (isMultiSelectDropDown) { this.get_items().clear(isMultiSelectDropDown); this._itemData = null; }; Telerik.Web.UI.RadComboBoxItemCollection.prototype.clear = function (isMultiSelectDropDown){ var f=this._parent._getControl(); if(f._checkBoxes){ f._checkedIndicesJson="[]"; f._checkedIndices=[]; var g = f.get_items(); for(var d=0,e=g.get_count();d<e;d++){ var c=f.get_items().getItem(d); c.set_checked(false, isMultiSelectDropDown); } if (isMultiSelectDropDown) { f._updateComboBoxText(); if (f._checkAllCheckBoxElement != null) { f._updateCheckAllState(); } } f.updateClientState(); } Telerik.Web.UI.RadComboBoxItemCollection.callBaseMethod(this, "clear"); }; Telerik.Web.UI.RadComboBoxItem.prototype.set_checked = function (d, isMultiSelectDropDown){ if(!this.get_enabled()){ return; } this._setChecked(d); var c=this.get_comboBox(); if(c){ if(d){ c._registerCheckedIndex(this.get_index()); }else{ c._unregisterCheckedIndex(this.get_index()); } if (!isMultiSelectDropDown) { c._updateComboBoxText(); } if((!isMultiSelectDropDown) && (c._checkAllCheckBoxElement!=null)){ c._updateCheckAllState(); } } }; } } /* Overriding Telerik functions End*/

    我的方法是默认保持旧的工作方式,但如果传递了isMultiSelectDropDown参数,则以优化的方式工作。所以我们将一个开关物化为参数,我们可以打开/关闭它。主要区别在于旧的方法是每次选中/取消选中复选框时更改显示所选元素的标签文本。主要改进是在选中/取消选中所有复选框后执行此更改。这个极其简单的想法是推动绩效背后的推动力。

    1. 实际使用情况

      overrideTelerikFunctionalities();
      combo.clearItems(true);
      
    2. 如果这些功能尚未完成且参数为真,则覆盖功能,因此选择了新方法。

      1. 测试,测试,测试