3

我有一个动态生成很多复选框(700+)的表单。表单在 IE 中加载非常缓慢(但在 chrome 中几乎没有加载),当我发布表单时,它几乎锁定了我的网络浏览器。

我该如何调试这个或者我做错了什么导致这个性能问题?或者这是预期的一个巨大的形式,我应该试着把它分开。

这是我的控制器:

public ActionResult Create(int id)
    { 
            var model = new TaskRequestViewModel
                {
                    Task = new Task(),
                    Components = db.Component.ToList()
                       …. 
                 }
            return View(model);           
    }

为了简要解释我的模型,我有大约 10 个组件,每个组件有大约 10 个子组件,每个子组件有大约 10 个选项(复选框)可用。导致上述 700 多个字段(然后是一些隐藏字段)。当复选框较少(100ish)时,它工作正常。

我的观点是这样的(有 3 个嵌套循环):

           @for (int cI = 0; cI < Model.Components.Count; cI++)
           {  
                    @Html.HiddenFor(x => Model.Components[cI].ComponentId)  

                    @for (int scI = 0; scI < Model.Components[cI].SubComponents.Count; scI++)
                    { 
                            @Html.DisplayFor(x => Model.Components[cI].SubComponents[scI].Name)                                 
                            @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].SubComponentId)

                            @for (int t = 0; t < Model.Components[cI].SubComponents[scI].TaskTypes.Count; t++)
                            {
                                @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].SubComponentTaskTypeId)
                                @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].TaskTypeId)
                                @Html.CheckBoxFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].Active)
                           } 

                    }

          }
4

4 回答 4

6

使用客户端验证时要注意的另一件事是 Html.HiddenFor。

当您使用jquery.validate.unobtrusive.js使用 MVC 项目中附带的默认包时,您将使用如下脚本渲染:

@Scripts.Render("~/bundles/jqueryval")

(注意:您可能已经更改了名称,这是默认值)

当你有了这个,任何 Html.HiddenFor 将呈现如下:

<input data-val="true" data-val-required="The XYZ field is required." name="XYZ" type="hidden" value="">

不用说,这些字段不需要启用客户端验证。用户看不到它们,也不能与它们交互,并且应该始终由您的模型填充。

解决这个问题的方法很简单:

@Html.HiddenFor(x => x.XYZ, new { data_val = "false" })

如果您不需要客户端验证,只需确保不包含捆绑包。

更多关于这里的阅读。

于 2014-08-28T11:03:12.017 回答
5

如果您使用 Visual Studio 性能分析器,您将通过第二级索引访问器看到您的渲染时间开始大幅上升。HiddenFor、EditorFor、LabelFor 等扩展可能非常密集,因为它们反映在您的模型上,以确定 ID、名称和数据注释的存在,同时它生成 HTML。

由于渲染需要很长时间,浏览器往往会冻结,因为它开始获取一些 HTML,但还没有全部获取,所以它会暂停。即使在加载了所有 HTML 之后,任何尝试在加载时运行的 JavaScript 库都需要评估(可能在许多字段上 - 这取决于您的业务逻辑,如果您使用的是 Modernizr、Html5Shi[v|m]、等)当您提交时,如果您使用不显眼的验证,您可能会被冻结,因为每个字段都被枚举并检查验证以及任何 OnSubmit 类型逻辑。

要加快渲染速度:

当您的模型使用多个级别的子级时,此执行会因许多记录而变得非常昂贵。不幸的是,只是将每个级别移动到自己的部分视图并传入父集合并不能 100% 解决问题。虽然它确实加快了速度,但您的模型名称不再正确生成。

例如,根据具有完整上下文链的模型,您的一个孩子的输入标签上的 Name 属性看起来类似于“Components[17].SubComponents[33].TaskTypes[5].SubComponentTaskTypeId”。如果您拆分到局部视图并将模型指定为 TaskType,当您尝试在第 18 个组件上渲染第 34 个子组件上的第 6 个时,名称现在将是“TaskType.SubComponentTaskTypeId”(假设您的模型是调用的 TaskType一个循环)或“TaskType[5].SubComponentTaskTypeId”(假设您的模型是一个调用一次的 IEnumerable)。

这意味着模型绑定器将不再知道如何将提交的表单转回完整的对象。

对我们来说,我们使用编辑器模板解决了这个问题。这些基本上是部分视图,但父级的上下文存储为 Prefix 属性,该属性自动附加到字段名称之前。它的性能要好一些(如果您要处理那么多字段,仍然不是很出色),并且名称仍然会以模型绑定器在发布到您的操作时可以理解的方式生成。

如果您对属性使用编辑器模板,则只需使用

@for (int t = 0; t < Model.Components[cI].SubComponents[scI].TaskTypes.Count; t++)
{
    @Html.EditorFor(m => m.TaskType[t])
}

如果它本身位于从 SubComponents[n] 调用的编辑器模板中,而该模板本身是从 Components[m] 调用的编辑器模板,那么您将维护全名解析。这是因为每个级别都会获取一次前缀并存储它,同时渲染子级,从而无需重复反映您的模型以生成名称。

作为奖励,您的视图更具可读性,并且您的显示逻辑现在按关注点(数据类型)分开,而不是混合在一起。

在提交时诊断冻结:

您需要运行一些 JavaScript 性能分析器来查看运行的内容和时间。查看正在加载哪些库,看看是否需要它们。如果你的包和 _layout 中有对 Modernizr 的默认 MVC 引用,那么你会受到巨大的打击。这部分调试很难指导,因为它依赖于所使用的客户端库。

编辑:在与遇到这种情况的同事交谈时(多行 3 个级别的孩子,每行有一个文本框、3 个输入、3 个链接和 5 个标签),他仍然无法为特定用户呈现如此多的记录要报告的异常高的行。数据太多,浏览器变得不稳定,偶尔会崩溃。

他最终使用 JavaScript 渲染模板来帮助解决这个问题。本质上,他为每一行加载了父级以及一个展开链接。单击它时,他将使用 AJAX 为子级获取 JSON 对象并使用渲染模板生成 HTML。当然,您必须小心为模型绑定器正确设置 id 和 name 属性以在提交时拾取它们,但这对他来说要好得多,因为没有一个父级有这么多行,以至于导致按需呈现问题. 我们的业务逻辑允许这样做,因为复选框基本上是作为从单个父级到其子级而不是跨父级的链运行的。这意味着当用户尝试工作或提交他们的更改时,如果不是所有的父母都完全加载并不重要。

于 2013-08-01T21:23:25.910 回答
0

要进行调试,请使用 Chrome 开发人员工具。然后查看网络选项卡并单击“保留导航记录”。https://developers.google.com/chrome-developer-tools/docs/network#network_panel_overview

完成后,提交您的表单并查看发布的内容。

于 2013-08-01T21:08:37.813 回答
0

在表单提交之前取消不显眼的验证也可以。

@onsubmit = "$('form').removeData('validator').removeData('unobtrusiveValidation'); return true;"
于 2020-09-17T20:47:59.577 回答