我正在构建一个购物车页面,该页面可能包含数十个单独的项目。每个项目都有一个可折叠面板,其中包含几个可用于自定义它的表单元素。大部分购物车都包装在UpdatePanel中,这样当用户进行更改时,我可以避免完整的回发。当购物车中有很多物品时,当然会有很多回发元素,所有这些元素都包含在原始表单帖子中,即使每个帖子实际上仅是由单个元素的更改触发的(ChildrenAsTriggers = True)。

我发现冗余表单名称/值对的未压缩大小为25K。实际上,由于浏览器中的gzip压缩,其大小可能要小得多(我假设浏览器会例行压缩回发值,但并没有费力去验证这一点-有人确定吗?)我知道我正在这里有点肛门(“在优化之前先进行配置!”),但是我真的很想找到一种消除这种冗余数据的方法。我想出了以下JavaScript:

Sys.WebForms.PageRequestManager.getInstance().add_beginRequest
(
  function(sender, args) {

    var elPostBackTrigger = args.get_postBackElement();

      // skip the first input element, which is expected to be the ScriptManager's hidden field
      removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("input"), elPostBackTrigger, 1);
      removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("select"), elPostBackTrigger);
      removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("textarea"), elPostBackTrigger);
   }
);

function removeNonEssentialPostBackValues(aElements, elPostBackTrigger, iFirstElement) {

    if (iFirstElement == undefined)
        iFirstElement = 0;

    for (var i = iFirstElement; i < aElements.length; ++i) {
        if
        (
            aElements[i] != elPostBackTrigger
            && aElements[i].name
            && aElements[i].name != ''
            && aElements[i].name.indexOf('_') != 0
        ) {
            aElements[i].removeAttribute('name');
            aElements[i].disabled = true;
        }
    }
}

这个想法是,如果删除表单元素的“名称”属性,则按照HTML规范,该属性将不再“成功”,并且ASP.NET应该从回发中将其忽略。当然,您不想弄混__VIEWSTATE,__ EVENTTARGET或其他任何以下划线开头的内容。而且您不想删除回发触发器本身。

不幸的是,这对通过Firebug捕获的回发值没有影响。看来,当PageRequestManager触发beginRequest事件时,它已经生成了回发名称/值对。我发现这很奇怪,因为我可以想象beginRequest事件的主要原因是在回发之前对表单元素进行了一些小的更改。也许PageRequestManager实际上并没有生成名称/值对,而是只是预先生成将包含哪些元素的列表?调试MS JavaScript库非常困难,我想知道是否有人可以启发我。

编辑1:除了删除它们的名称属性外,我还尝试禁用表单元素,但这无济于事。我通过Firebug验证了这些元素已被禁用,并且在beginRequest事件完成之前已删除它们的名称,但是以某种方式,ASP.NET仍将它们全部添加到回发中。

乔丹·里格(Jordan Rieger)

最佳答案

我终于遍历了MicrosoftAjaxWebForms.debug.js,并验证了PageRequestManager确实在引发beginRequest事件之前确实生成了post集合。更糟糕的是,该集合存储在StringBuilder中的局部变量中,因此即使我愿意访问私有(private)成员,我也无法操纵它。
我发现的解决方案是在后面的代码中从Page_Load调用ScriptManager.RegisterOnSubmitStatement,以设置JavaScript beforePostback()函数。我验证了确实在PageRequestManager开始其肮脏的工作之前调用了此函数,因此可以在其中放置对removeNonEssentialPostBackValues()的调用。

    If Not ScriptManager.GetCurrent(Me).IsInAsyncPostBack Then
        ScriptManager.RegisterOnSubmitStatement(Me, Me.GetType(), "beforePostback", "beforePostback()")
    End If
和JavaScript:
function beforePostback() {
    var nlTriggers = document.getElementsByName(document.aspnetForm.__EVENTTARGET.value);
    if (nlTriggers && nlTriggers.length > 0) {
        var elPostBackTrigger = nlTriggers[0];
    }

    // skip the first input element, which is expected to be the ScriptManager's hidden field
    removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("input"), elPostBackTrigger, 1);
    removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("select"), elPostBackTrigger);
    removeNonEssentialPostBackValues(document.aspnetForm.getElementsByTagName("textarea"), elPostBackTrigger);
}
有了这段代码,我发现在手工制作的噩梦场景中,我可以将回发请求的大小从大约34,000减少到大约15,000。我还验证了重要的表单值仍在传递给页面,并且后面的代码仍可以辨别哪个元素触发了回发。
显然,此技术是非常笨拙的,因此不适合许多情况。例如,在典型的Web表单场景中,用户必须编辑多个字段并通过验证,因此您不想这样做,因为您需要发布所有表单值。实际上,这项技术是一种更接近客户端接口(interface)的简单方法,在该接口(interface)上,JavaScript仅执行执行其命令所需的最少服务器调用。在性能非常好之前,我已经构建了这样的应用程序,但是它们对开发和维护很乏味。对于这个项目,我想在保持高性能的同时尽可能地利用ASP.NET。
更新:我刚刚在IE 8中进行了测试(我一直在使用Firefox 3.6),并且禁用成百上千的表单元素是一个非常缓慢的过程。它需要1或2秒的时间,而Firefox 3.6甚至不会眨眼。我不禁思索IE 7可能有多慢。我想我现在将不得不放弃这种技术,因为为大量IE用户引入的延迟将比不必要的表单元素额外的20K回发数据所导致的延迟大得多。
更新2:如果十年后仍在维护复杂的ASP.NET WebForms页面(我很同情),您可能会发现现代浏览器和设备几乎可以立即在我的辅助函数中通过JS进行播放。

关于javascript - 如何在ASP.NET异步回发之前禁用或删除不必要的表单元素?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3983539/

10-09 16:38
查看更多