提交大量元素MVC

时间:2015-01-20 15:09:58

标签: jquery asp.net-mvc optimization jquery-validate unobtrusive-validation

编辑:jqueryval是罪魁祸首(不引人注意吧?)。不知道为什么它会影响任何东西,因为我们在设置中的复选框上禁用了它。但是,对引用进行注释会使加载时间变得不可察觉。我已经尝试了几个没有运气的修复。

这是导致减速的函数,jquery.validate.js中的第532行

elements: function() {
            *snip*
            return $( this.currentForm )
            .find( "input, select, textarea" )
            .not( ":submit, :reset, :image, [disabled], [readonly]" )
            .not( this.settings.ignore )  //performance murderer
            *snip*
        },

*注意 - 我在此之后剪切了过滤器功能,因为在测试中我没有使用它并仍然减速,所以它并不真正相关。

我也从验证中删除了复选框:

    $.validator.setDefaults({
        ignore: ":hidden, input[type=checkbox]" //do not validate checkboxes
    });

我有一个mvc应用程序,它将在2000+以上的复选框中发回服务器。这通常不是问题,通过jquery选择器与站点的交互运行完全正常,加载时间很快。但是,提交会导致某种重排问题,其中每个文本框及其标签offsetHeight和offsetWidth都会被检查。在创建和保存编辑时,这会加剧超过5秒的加载时间。

...开始 Initial UI Report

...完 enter image description here

(我很确定它刚刚在那里放弃了,但是有2000多个事件你可以滚动它几分钟)

初始负载会受到影响,但随着用户更多地使用该网站,其中许多复选框将被“禁用”,我理解这意味着他们将不再发布回复。不幸的是,禁用这些文本框并不会导致元素的数量回发丢弃。我觉得这与MVC有关,但这里是代码:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()


    <fieldset>
        <legend><input type="submit" value="Create"/> | @Html.ActionLink("Back to List", "Index", "CatManager")</legend>

        @if (Model.CategoryViewModel.ChildCategoryNodes.Any())
        {
            for (int i = 0; i < Model.CategoryViewModel.ChildCategoryNodes.Count(); i++)
            {
                @Html.HiddenFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Id)
                @Html.HiddenFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Description)
                <label @(Model.CategoryViewModel.ChildCategoryNodes[i].CategoryId != null ? "disabled" : "")>
                    @if (!Model.CategoryViewModel.ChildCategoryNodes[i].AlreadyTaken)
                    {
                       @Html.CheckBoxFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Selected, new Dictionary<string, object> {{"data-id", Model.CategoryViewModel.ChildCategoryNodes[i].Id}, {"data-description", Model.CategoryViewModel.ChildCategoryNodes[i].Description}}) 
                    }
                    else
                    {
                        @Html.CheckBoxFor(model => model.CategoryViewModel.ChildCategoryNodes[i].Selected, new Dictionary<string, object>{{"data-id", Model.CategoryViewModel.ChildCategoryNodes[i].Id}, {"data-description", Model.CategoryViewModel.ChildCategoryNodes[i].Description}, {"disabled","disabled"}})
                    }
                    @Model.CategoryViewModel.ChildCategoryNodes[i].Id - @Model.CategoryViewModel.ChildCategoryNodes[i].Description
                </label>
            }
        }
    </fieldset>
}

任何人都知道如何减少被回收的垃圾量,或者如何避免这种超慢速偏移回流?

编辑:像往常一样,我受到那些认为他们知道这里发生了什么的人的骚扰,但他们显然没有,所以这里有一些示例代码在不到一秒的时间内运行,每次运行在我的dom上字符被输入到文本框中。

    $("#filter").on("keyup", function() {
        ValidateTextBoxes();
    });

    function ValidateTextBoxes() {
        $("input[type=checkbox]").each(function() {
            var val = $("#filter").val();
            var id = $(this).data("id");
            var description = $(this).data("description");
            if (val != null && id != null && description != null) {
                if (id.toString().indexOf(val.toString()) > -1 || description.toString().toLowerCase().indexOf(val.toString().toLowerCase()) > -1){
                    $(this).parent().show();
                } else {
                    $(this).parent().hide();
                }
            }
        });
    }

所以,感谢,不再有关于元素数量的评论。

2 个答案:

答案 0 :(得分:3)

即使OP不想听到这个问题,我也会冒险尝试为这个问题提供有用的答案。我回复了the last question you posted regarding these same 2k checkboxes,我仍然坚信你正试图解决错误的问题。也许这就是为什么这么多人给你的答案,你似乎不想听到。

在您的上一个问题中,您表示漫长的等待时间使您调试和开发非常令人沮丧。我建议你重新考虑一下你的用户界面,我接受了#34的效果声明;如果我想帮助写一个更好的用户界面,我会要求它#34;。您还表示您计划重写UI,但与此同时,这些浏览器性能问题使您无法完成中间工作。

您可以做的一件事是临时更改您的测试数据或控制器操作,以便它只返回20个复选框而不是2000.这样的事情可以帮助您更快地工作,直到您可以重新设计用户体验。如果您计划在生产中为用户呈现2000个复选框,那么期望他们的用户体验很差。

我不知道关于jqueryval的问题的答案,所以请随意关注这个答案。但是我确实知道浏览器javascript引擎(尤其是IE)会在尝试扫描并使用它们时阻塞非常大的DOM。技术只会带你到目前为止,你必须愿意妥协并在中间的某个地方遇见浏览器。

如果您还没有完成,我建议的另一件事是阅读jqueryval源代码。

<强>更新

this.settings.ignore的默认值似乎是':hidden',如下所示:

$.extend($.validator, {

    defaults: {
        messages: {},
        groups: {},
        rules: {},
        errorClass: "error",
        validClass: "valid",
        errorElement: "label",
        focusInvalid: true,
        errorContainer: $([]),
        errorLabelContainer: $([]),
        onsubmit: true,
        ignore: ":hidden", // HERE
        ignoreTitle: false,
        onfocusin: function( element, event ) {

而不是分支jqueryval,看看这样做是否会提高性能:

$.validator.setDefaults({ ignore: '' });

参考文献是:

asp.net mvc: why is Html.CheckBox generating an additional hidden input

jQuery Validate - Enable validation for hidden fields

如果忽略设置确实是性能凶手,那么我希望将它设置为空字符串应该使过滤选择器短路并让你回到&#34;正常&#34; 2k +复选框的性能(加上2k +隐藏输入,总共需要4k +元素来渲染所有类别)。

答案 1 :(得分:0)

好吧,所以...

问题是jqueryval,我们的答案是在提交按钮上添加cancel类以专门阻止此页面上的jqueryval,然后使用ValidatorContext在进入控制器时验证模型。

我们为无法回发的属性(例如,下拉列表的内容)重新水化,并将其发回给用户,由普通的mvc validationsummary处理。

    [HttpPost]
    public ActionResult Create(EditFirstChildCategoryViewModel editFirstChildCategoryViewModel)
    {
        if (!ModelState.IsValid)
        {
            var categories = _categoryDataService.GetRootCategoryModels();

            editFirstChildCategoryViewModel.ExistingCategoryDropDown =
                _selectListFactory.CreateSelectList(categories, RootCategoryValueExpression,
                    RootCategoryTextExpression);

            return View(editFirstChildCategoryViewModel);
        }
        //etc...
    }

用户可以解决任何问题,我们会让我们糟糕的可怕的2000复选框设计表现出来。