Событие JS onunload не всегда работает - PullRequest
5 голосов
/ 29 ноября 2010

Я хочу посчитать, сколько времени посетители проводят на определенной странице, и сохранить ее в моей базе данных MySQL.

Я думал о том, чтобы просто запустить таймер в window.onload, как это:

window.onload= startCount;
window.onunload= sendCount;

var b=0;
var y;
function startCount() {
    document.getElementById('livecount').innerHTML=b;
    b=b+1;
    y=setTimeout("startCount()",1000);
}

и после того, как посетитель покидает страницу (window.onunload), я отправляю время через XMLHttpRequest в файл PHP, который сохранит его в моей БД:

function sendCount() {
    clearTimeout(y);    
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }  
xmlhttp.open("GET","count.php?q="+b,true);
xmlhttp.send();
}

Проблема в том,это не всегда работает.Я бы сказал, что это работает как 3 из 10 раз, когда я пытаюсь это сделать.Может ли быть так, что для полного выполнения PHP и SQL не хватает времени?

Ответы [ 5 ]

4 голосов
/ 30 ноября 2010

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

Я бы разбил время на интересующие вас периоды, такие как <5 секунд, <30 секунд, <1 минута, <5 минут, 5+ минут. </p>

Тогда я бы написал кусок JavaScript примерно так:

window.onload = soCounter;

var iter=0;
var times=[0,5,30,60,300];  // Your duration choices

function doCounter() {

    sendCountPing(times(iter));

    iter++;

    if(iter < times.length) {
        setTimeout(doCounter, times[iter]*1000);
    }
} 

function sendCountPing(dur) {
    if (window.XMLHttpRequest)
    {  // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    }
    else
    {  // code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }  

    xmlhttp.open("GET","count.php?q="+b,true);
    xmlhttp.send();

}

Хитрость в том, что для каждой отправляемой count.php?q=30 вам нужно вычесть одно из числа count.php?q=5. Это не обязательно должно быть программно, оно легко обрабатывается.

Для уточнения: если у вас было 3 посетителя, один потратил 3 секунды, один потратил 20 секунд, а другой потратил 30 минут, вы увидите следующие значения:

  0:  3   // 3 people spent at least 0 seconds
  5:  2   // 2 people spent at least 5 seconds
 30:  1
 60:  1
300:  1   // 1 person spent at least 5 minutes

Имеет смысл?

1 голос
/ 30 ноября 2010

Вы можете настроить таймер в соответствии с предложением, который будет работать так часто, как вы хотите (каждые несколько секунд или около того), и сохранять информацию в куки (или куки). Вы можете отправить эту информацию на сервер, если это необходимо, если вы хотите сделать что-то большее, чем отображение значения для пользователя. Поэтому не отправляйте его на сервер каждый цикл, просто отправляйте его на сервер, если вы хотите что-то сделать с этой информацией (например, отобразить пользователю список всего времени, которое он провел на разных страницах вашего сайта). 1001 *

1 голос
/ 30 ноября 2010

к тому времени, когда запускается обработчик загрузки, страница находится в процессе удаления. Я не уверен, какие у вас гарантии для состояния DOM или других служб, но вы, конечно, не можете ожидать, что сработают события асинхронности или тайм-ауты. Хотя сегодня это не входит в стандарт, большинство (всех?) Браузеров предоставляют хук onbeforeunload , который работает так же, как и другие обработчики событий, за исключением того, что вы также можете вернуть false, чтобы отменить выгрузку, если вы выберете.

0 голосов
/ 24 ноября 2015

Другой вариант - сохранить данные в localStorage / cookie и отправить их в следующий раз, когда пользователь заходит на сайт; при условии, что пользователь останется или когда-либо вернется на ваш сайт.

Лучше использовать Date() calc вместо setInterval/setTimeout для подсчета времени.
Лучше использовать addEventListener вместо onload = func.

sendPreviousStats();
window.addEventListener('load',loadFunc);
window.addEventListener('unload',leaveFunc);

function loadFunc() {
    window.startTime = new Date();
}

function leaveFunc() {
    var msec = new Date().getTime()-window.startTime.getTime();
    var seconds = Math.round(msec/1000);
    localStorage.setItem('leaveSeconds',seconds);
}

function sendPreviousStats() {
    var duration = localStorage.getItem('leaveSeconds');
    if (duration !== null && duration !== undefined) {
        localStorage.removeItem('leaveSeconds');
        sendCountPing(duration);
    }
}
0 голосов
/ 29 ноября 2010

onunload не надежный способ отследить ... ну, в общем-то, что угодно.например, см. http://www.google.com/support/forum/p/Google+Analytics/thread?tid=6496cd5d4b627c0e&hl=en

Что касается решения проблемы, лучший способ - отслеживать, когда пользователь в последний раз был на странице.Например звоните трекеру каждую минуту с клиента.Аналитические системы, такие как Google Analytics, фактически предполагают, что пользователь ушел после последней обработанной страницы.Т.е. если я прочитаю страницу и затем нажму на что-то, она обновит счетчик.Но если никаких последующих попаданий не происходит, значит, я ушел.

...