onbeforeunload не всегда работает

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

window.onload = function() {


var timeStarted, i, c, l, timeLeft, pageData; 

timeStarted = new Date().getTime();

i = <?php echo $model->id; ?>;
c = <?php echo $model->cat; ?>;
l= <?php echo $model->loc; ?>;

window.onbeforeunload = function(){

timeLeft = new Date().getTime();

pageData = [{name: 'timeStarted', value: timeStarted}, 
            {name: 'i', value: job},
            {name: 'c', value: cat},
            {name: 'l', value: loc},
            {name: 'timeLeft', value: timeLeft}];

// Set url for JavaSCript
var url = '<?php echo Yii::app()->createUrl("item/viewedItemInformation"); ?>';

<?php echo CHtml::ajax(array(
        'url'=>'js:url',
        'data'=> "js: pageData",
        'type'=>'post',
        'dataType'=>'json',
        )); ?>;             
}
}

Примечание

Я только что прочитал этот пост window.onbeforeunload не работает в chrome, и я использую хром. Однако я, кажется, получаю те же результаты и в FF.

Как правильно решить эту проблему?

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


person Jonnny    schedule 16.09.2013    source источник
comment
Вы не можете надежно выполнять запросы AJAX от beforeunload. Этот обратный вызов никогда не предназначался для этого.   -  person meagar    schedule 16.09.2013
comment
@meagar Спасибо, есть ли обходной путь, чтобы в основном иметь возможность скоротать время, когда пользователь загружал, а затем вообще покидал определенную страницу?   -  person Jonnny    schedule 16.09.2013
comment
Нет, нет, но в зависимости от того, насколько точным это должно быть, вы можете отправлять запрос через регулярные промежутки времени, и когда он останавливается, пользователь уходит, а в HTML5 также есть Page Visibilty API, который может быть полезен.   -  person adeneo    schedule 16.09.2013


Ответы (3)


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

Я думаю, что проблема, с которой вы столкнулись, заключается в том, что браузер или операционная система клиента перестают отвечать/работать. Получить 100% данных в любой ситуации было бы крайне сложно, если вообще возможно.

При этом вы не уточнили, что вы думаете о ситуациях, когда событие onbeforeunload не работает, поэтому вы оставили свой вопрос слишком открытым для субъективности. Если вы обновите свой вопрос и тогда прокомментируете мой ответ, я буду рад изменить его, чтобы сделать его более конкретным.


Что можно попробовать протестировать...

1.) Щелкните локальную ссылку (ссылку на вашем сайте на другую страницу вашего сайта).

2.) Щелкните внешнюю ссылку.

3.) Закройте вкладку.

4.) Закройте окно.

5.) Убейте процесс браузера с помощью диспетчера задач/эквивалента.

6.) Вытащите вилку из розетки на компьютере, чтобы имитировать отключение питания.


Согласно Mozilla Dev Network...

Since 25 May 2011, the HTML5 specification states that calls to 
window.showModalDialog(), window.alert(), window.confirm(), and window.prompt()
methods may be ignored during this event.

https://developer.mozilla.org/en-US/docs/Web/API/Window.onbeforeunload

Поэтому имейте в виду, что эти методы могут не работать в некоторых браузерах, если поддерживается onbeforeunload. В этом случае вы можете попытаться пропинговать сервер с помощью запроса AJAX и просто посмотреть журнал доступа Apache для запроса, обычно вы можете отправить объект/данные/текст/и т. д. JavaScript в виде HTTP-запроса, например, request.php?q=javascript-object, чтобы вы могли визуально подтвердите, делает ли браузер то, что вы думаете/хотите.

person John    schedule 16.09.2013
comment
Обновил мой код, хотя он действительно спорадический. Я также не осознавал, что добиться этого так сложно, что заставляет меня задаться вопросом, как Google Analytics справляется с этим. - person Jonnny; 17.09.2013
comment
Я добавил несколько сценариев для вас, чтобы попробовать. Я рекомендую попробовать каждый из них по крайней мере три или четыре раза и каждый раз записывать то, что вы находите. Это должно помочь вам решить, какие сценарии вы можете надежно записывать данные, а какие нет. Вы также можете использовать (предпочтительно более старую) версию Fiddler, если вы используете Windows для просмотра запросов таких вещей, как Google Analytics. - person John; 17.09.2013
comment
Привет, @John, вчера вечером я снова начал смотреть на это. Я нашел это непоследовательным, используя onbeforeunload(), и я не мог работать, когда он не работал, используя ваши полезные советы выше, просто иногда это работало, а иногда - нет. Поэтому я начал присматриваться к таким вещам, как Piwiks. Потом я немного отвлекся от всего этого. Что касается надежности, я обдумывал идеи и подумал, что будет проще просто поместить информацию в сеанс php. Таким образом, каждый раз, когда вы посещаете страницу, она регистрирует идентификатор и время. Тогда просто вычислить разницу во времени и записать строку в БД? - person Jonnny; 20.11.2013
comment
@Jonnny Ну, я обновил свой ответ, потому что я действительно наткнулся на страницу MDN, а затем нашел эту страницу со своим ответом. Прочитайте нижний раздел, я сделал еще одно предложение для визуального подтверждения, работает ли onbeforeunload или нет. - person John; 21.11.2013
comment
Спасибо за это, из того, что я делал ранее и читал здесь подобные вопросы, я пришел к общему мнению, что метод onbeforeunload() никогда не создавался для той цели, с которой я пытался его использовать, и он всегда будет быть очень хитом и пропустить, успеют ли данные быть записаны. Что, я думаю, имеет смысл. Не могли бы вы увидеть ответ ниже как разумную альтернативу тому, что я пытаюсь сделать? - person Jonnny; 21.11.2013
comment
Переместите свой скрипт в window.onload = function() {/*here*/} и посмотрите, работает ли он; если нет, то сначала исправьте его там и ПОТОМ переместите его в событие onbeforeunload. Вы даже не уточнили, с каким браузером у вас проблемы. Поэтому сначала убедитесь, что ваш скрипт делает то, что ему нужно (связывается с вашим сервером от клиента во время события onload), а затем, как только вы подтвердите (или исправите и затем подтвердите), протестируйте его с помощью onbeforeunload событие; затем сообщите нам, что произошло, и ТАКЖЕ сообщите нам, какой браузер не работает... и обязательно протестируйте в Chrome И Firefox минимально. - person John; 22.11.2013

Событие onbeforeunload срабатывает только в том случае, если было ЛЮБОЕ взаимодействие пользователя с сайтом. Без ЛЮБОГО события взаимодействия (например, клика, а не наведения) на вашей странице onbeforeunload не будет запущено.

person aermin    schedule 11.11.2020

Пока вот как я это сделал. Возможно, это будет полезно другим, если нет и с этим есть проблемы, я удалю ответ.

Когда я загружаю страницу элемента, я обновляю свою БД с идентификатором, категорией, идентификационным номером, местоположением, временем начала использования NOW(), а также обновляю оставшееся время как NOW().

Затем на самой странице я запускаю этот javascript.

<script>

// Set url for JavaSCript
var url = '<?php echo Yii::app()->createUrl("item/viewedItemInformation"); ?>';
var item = '<?php echo $model->id; ?>';

var data = [{name: 'item', value: item},
    {name: 'async', value: false}];

// call function to see if still on page
var onPage = setInterval(function() {

<?php echo CHtml::ajax(array(
        'url'=>'js:url',
        'data'=> "js: data",
        'type'=>'post',
        'dataType'=>'json',
    )); 
?>              

}, 5000);

So that script runs every 5 seconds and calls another controller function that searches for the record in the DB and updates the time_ended with the time the controller function was called using NOW() also.

Надеюсь, это имеет смысл, я только немного протестировал его, поэтому мне нужно будет сделать с этим немного больше. Если кто-то увидит какие-либо проблемы с ним, дайте мне знать.

Обновить

Пока этот скрипт работает нормально. Я работаю только на своем локальном хосте, и у меня есть плагины LinkedIn, и они, похоже, останавливают работу скрипта. Я продолжаю получать эту ошибку: я никогда не замечал этого раньше. Недавно я переустановил свой XAMPP, поэтому, возможно, я не знаю о каких-либо других различиях между setup. Я также не уверен, почему плагин может остановить работу моего JS-скрипта?

Origin http://localhost is not allowed by Access-Control-Allow-Origin.

Джонни

person Jonnny    schedule 20.11.2013