'onbeforeunload' срабатывает дважды

Я хочу отправить запрос ajax, когда пользователь покидает страницу или закрывает окно.
Вот мой код внутри:

<script type="text/javascript">
    function sendajax(){
        $.ajax({
          url: "someurl",
          data: mydata,
          async : false
        });   
    }
</script>
    <script type="text/javascript">
     window.onbeforeunload=function(){sendajax();};
</script>   

Когда событие происходит, оно срабатывает дважды.
Почему это происходит?
Я знаю, что могу предотвратить это, добавив переменную var ajaxSent=true;, но, может быть, есть более чистый способ сделать это?

UPD:
Я заменил содержимое функции sendajax другим кодом (без отправки ajax) и обнаружил, что проблема не в ajax. Он по-прежнему входит в функцию дважды.


person lvil    schedule 03.01.2012    source источник
comment
На странице есть фреймы?   -  person beeglebug    schedule 03.01.2012
comment
Нет, это часть тестовой страницы, на которой есть только текст и ссылка   -  person lvil    schedule 03.01.2012
comment
Можете ли вы привести пример? Кроме того, в каком браузере вы видите это?   -  person beeglebug    schedule 04.01.2012
comment
это единственный код после тега заголовка: '‹body› sssssss ‹a href=www.ww› abc‹/a› ‹/body›' Я пробовал это в Chrome16 и Firefox3.6 на Ubuntu   -  person lvil    schedule 04.01.2012
comment
Странно, я не могу заставить событие запускаться несколько раз на моем компьютере с Windows 7 в любом браузере. Если вы попробуете этот jsFiddle, который имитирует ваш код: jsfiddle.net/rWKdR, произойдет ли это дважды?   -  person beeglebug    schedule 04.01.2012
comment
Я думаю, у меня это есть! Похоже, что тег A вызывает ошибку или, скорее, хитрый href. Я только что изменил свой ответ ниже, чтобы отразить то, что я только что нашел, с примером.   -  person beeglebug    schedule 04.01.2012
comment
Большое спасибо @beeglebug!!!!! Проблема заключалась в том, что ссылка была www.www - когда я изменил ее на www.google.com, она отлично заработала. Просто напишите это как ответ, чтобы я мог проголосовать за него.   -  person lvil    schedule 04.01.2012


Ответы (5)


Основываясь на коде в вашем редактировании и комментариях, похоже, что это может быть просто вызвано неработающей ссылкой, по которой вы нажимаете, чтобы покинуть страницу.

Учитывая следующий код:

<script>
    function doSomething() { console.log('onbeforeunload fired'); }
    window.onbeforeunload = doSomething;
</script>
<a href="garbage">link A</a>
<a href="http://google.com">link B</a>

Если я нажму на ссылку A, я получу две записи журнала консоли, если я нажму на ссылку B, я получу только одну.

Похоже, что это может быть причудой того, как браузеры обрабатывают свои внутренние страницы «Эта веб-страница не найдена», в результате чего ваша страница обновляется и снова закрывается перед отображением сообщения, оставляя вас с двумя экземплярами события onbeforeunload.

person beeglebug    schedule 03.01.2012
comment
Я обнаружил, что поведение события beforeunload значительно различается (особенно в отношении того, сколько раз оно вызывается) в зависимости от режима документа IE. более новое и более стандартное поведение срабатывает реже, чем более старое поведение обратной совместимости (IE10). - person BlueMonkMN; 12.07.2017

У меня была та же проблема, и мне потребовалось некоторое время, чтобы понять и решить, поделившись подробностями дела:

В нашем шаблоне был собственный JS, который управлял меню. Это привело к тому, что выгрузка сработала дважды, только при нажатии на ссылки меню, а не на другие ссылки, и только в IE/EDGE.

В конце концов мы остановили распространение по этим ссылкам, и проблема была решена.

$('.SELECTOR a[href^="http://"]').on('click', function(e){
    e.stopPropagation();
});

Это конкретная ошибка в вашем приложении, поэтому в гугле вы не найдете слишком много информации.

person AlonMichaeli    schedule 10.12.2018

Вы можете попробовать следующий код:

<script type="text/javascript"><br>
     window.onbeforeunload=function sendajax(){<br>
        $.ajax({<br>
          url: "someurl",<br>
          data: mydata,<br>
          async : false<br>
        });<br>
};<br>
</script>

или вы можете определить sendajax() {} в каком-то месте и использовать его как onbeforeunload = "sendajax()", а не как onbeforeunload = "function () { sendajax() }"

person me_digvijay    schedule 03.01.2012
comment
Какова цель именования встроенной функции? Вы не можете ссылаться на sendajax после этого, это кажется излишним. - person beeglebug; 03.01.2012
comment
@beeglebug: Вы правы, это тот случай, когда вы хотите использовать функцию только один раз. Если вы хотите использовать функцию, вы можете определить ее в другом месте и вызывать как onbeforeload =sendajax(), а не как onbeforeload =function(){sendajax()}, потому что здесь sendajax сначала вызывается два раза при определении функции (обратите внимание, что не sendajax() является внешним), и после определения сама внешняя функция вызывается один раз, что снова вызывает sendajax(). - person me_digvijay; 03.01.2012
comment
У меня есть изменения 'window.onbeforeunload=function(){sendajax();};' в 'window.onbeforeunload=sendajax();' и 'window.onbeforeunload=sendajax();;' и 'window.onbeforeunload=sendajax;'. Ничего из вышеперечисленного не работало вообще. Функция просто не выполнялась. - person lvil; 04.01.2012
comment
Вы также можете вызвать функцию как window.onbeforeunload = sendajax; и вы должны передать аргумент события функции sendajax при определении подобной функции sendajax(e) {} - person me_digvijay; 04.01.2012

beforeUnload можно отменить

Я знаю, что этот пост довольно старый, но из документации API Chrome Pagelifecycle браузеры могут иногда частично выгружать страницы для экономии ресурсов. https://developers.google.com/web/updates/2018/07/page-lifecycle-api beforeUnload не обеспечивает надежного закрытия страницы. Особенно это происходит на устройствах Android, когда экран заблокирован.

Я обнаружил, что есть jsfiddle, который кто-то написал, и вы можете протестировать https://jsfiddle.net/ov6b9pdL/. Держите экран заблокированным в течение 5-10 минут в Chrome Android, и вы увидите, что beforeUnload запускается, даже не закрывая вкладку.

$(document).ready(function() {
    window.addEventListener('beforeunload', showLoader);
});

var showLoader = function() {
    $('#loader').show();
};
person Winston Jude    schedule 24.04.2020

Согласен с концепцией Алона Михаэли. В моем приложении был тег привязки, завернутый в div вместе с парой спанов. Когда Anchor нажали на грязную страницу, появилось несколько уведомлений «Покинуть сайт». Он работал нормально, если щелкнуть любую другую часть menuItem (div или span). Поэтому в пользовательском методе javascript я добавил остановленное распространение и preventDefault, только если щелкнут тег привязки. Как-то в этом случае нужен preventDefault.

function menuItemClicked(event: JQueryEventObject) {
  var item = $(event.target);
  if (item.is(".anchor-item")) { 
    event.stopPropagation();
    event.preventDefault();
  }
  href = item.closest(".anchor-item").attr("href");
  if (!event.ctrlKey && href) {
    window.location.href = href;
  }
}
person Kumar Shishir    schedule 04.05.2021