Обтекание веб-формы ASP.NET с div вызывает двойную асинхронную обратную передачу, но только с jQuery, а не с обычным DOM. Зачем?

Почему это происходит?

  1. Возьмите простую веб-форму ASP.NET с одной UpdatePanel и кнопкой.
  2. В удобной функции события pageLoad на стороне клиента ASP.NET (если хотите, используйте готовый JQuery DOM), оберните элемент формы во вновь созданный элемент div с помощью jQuery.
  3. Нажмите на кнопку и обратите внимание, что отправляются два асинхронных (xhr) постбека (для их просмотра используйте вкладку "Сеть" в инструментах разработчика браузера F12).

Вот пример кода, чтобы воспроизвести проблему:

<%@ Language="C#" %>
<!DOCTYPE html>
<html>
<head><title>Double async postback when form element wrapped in new div after page load</title></head>
<body>
    <form id="frmTest" runat="server">
        <asp:ScriptManager ID="smTest" runat="server" ScriptMode="Release" />
        <asp:UpdatePanel ID="upTest" runat="server">
        <ContentTemplate>
            <asp:Button ID="btnTest" runat="server" Text="Test Postback"/>
        </ContentTemplate>
        </asp:UpdatePanel>
    </form>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">
        function pageLoad() {
            // jQuery:
            $("<div></div>").insertBefore("form").append($("form"));
            // DOM-only:
            //document.body.insertBefore(document.createElement("div"), document.forms[0]).appendChild(document.forms[0]);
        }
    </script>
</body>
</html>

(Я использую простой файл web.config для.NET Framework 4.5.2 и jQuery 1.7.1. Мне удалось воспроизвести это в Firefox 40.0.3, Chrome 45.0.2454.85 и IE 11.)

Теперь обратите внимание, что если вы закомментируете строку jQuery и раскомментируете строку только для DOM, отправляется только один постбэк.

Кроме того, если вы оборачиваете тег формы в div перед загрузкой страницы (то есть в статическом HTML), он работает нормально (без двойной обратной передачи.)

Почему это важно / почему меня это волнует? Многие плагины jQuery (например, jPanelMenu) обертывают все содержимое тега body (или большинство из них) в div, чтобы обеспечить относительно расположенного предка.

1 ответ

Решение

Так что, как это часто бывает, в процессе составления правильного вопроса с максимально полным и лаконичным демонстрационным кодом, я полагаю, я нашел ответ.

Я обнаружил, что если я обновлю jQuery до 1.9.0, проблема исчезнет. Но согласно их документации, в версии 1.9.0 произошло много изменений, которые потенциально могли сломать старые плагины (которых в моем проекте несколько.) У меня есть ощущение, что эта проблема связана с этим изменением в 1.9.0:

Загрузка и запуск скриптов внутри содержимого HTML

До версии 1.9 любой принимающий HTML-метод (например, $(), .append() или.wrap()) выполнял любые сценарии в HTML и удалял их из документа, чтобы предотвратить их повторное выполнение. Это все еще ломалось в ситуациях, когда скрипт мог быть удален и вставлен в документ с помощью таких методов, как.wrap(). Начиная с версии 1.9, сценарии, вставленные в документ, выполняются, но остаются в документе и помечаются как уже выполненные, поэтому они не будут выполняться снова, даже если они будут удалены и вставлены заново.

Каждая веб-форма ASP.NET с элементами управления ScriptManager/UpdatePanel имеет эти WebResource.axd и ScriptResource.axd. <script> теги вставляются в нижней части содержимого элемента формы. Они предоставляют клиентскую среду AJAX. Я считаю, что jQuery перезагружал эти сценарии, когда он добавлял узел формы к новому узлу div, и, следовательно, дублировал обработчики событий обратной передачи. Теперь мой единственный вопрос: почему мне было так трудно это обнаружить? Я не видел каких-либо дополнительных обработчиков событий или дополнительных поисков сценариев (даже кэшированных). Но это отдельный вопрос...:)

Другие вопросы по тегам