问题
I want to count how much time visitors spend on a certain page and store it in my MySQL DB.
I thought of just starting a timer on window.onload like this:
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);
}
and after the visitor leaves the page (window.onunload), I'm sending the time through an XMLHttpRequest to a PHP file, which will store it in my DB:
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();
}
The problem is it doesn't always work. I would say it works like 3 out of 10 times I try it. Could it be that there is not enough time left for the PHP and SQL to be completely executed?
回答1:
As onunload is unreliable, I would consider an AJAX solution. I am not an expert in this at all, but the thought that comes to mind is a ping to your counter every so often. I wouldn't ping your counter every second, as that seems excessive.
I would break down times into durations you care about, such as <5 seconds, <30 seconds, <1 minute, <5 minutes, 5+ minutes.
Then I would write a piece of JavaScript like so:
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();
}
The trick is that for every count.php?q=30
that gets sent, you need to subtract one from the count.php?q=5
count. This does not have to be programmatic, it is easily post-processed.
To clarify, if you had 3 visitors, one spending 3 seconds, one spending 20 seconds, and one spending 30 minutes, you would see the following counts:
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
Make sense?
回答2:
by the time the onload handler runs, the page is in the process of being taken down. I'm not sure what guarantees you have for the state of the DOM or other services, but you certainly can't expect asynch events or timeouts to fire. Though not part of the standard, most (all?) browsers today provide an onbeforeunload hook which works much the same way as other event handlers, except that you can also return false to cancel the unload if you choose.
回答3:
You could set up a timer as suggested which runs as often as you want (ever few seconds or so), and store the information in a cookie (or cookies). You can send this information to the server if needed when you want to do something more than displaying the value to the user. So don't send it to the server every cycle, just send it to the server when you want to do something with that information (like display to the user a list of all the time he spent on various pages on your site).
回答4:
onunload is not a reliable way to track ... well, pretty much anything. for example see http://www.google.com/support/forum/p/Google+Analytics/thread?tid=6496cd5d4b627c0e&hl=en
As far as solving the issue, the best way is to track last time the user was on the page. For example call the tracker every minute from the client. Analytics systems like Google Analytics actually just assume user left after the last page that was served. I.e. if i read the page and then click on something, it refreshes the counter. But if no subsequent hits happen, that means that I left.
回答5:
Another option is to save the data in localStorage/cookie and send it the next time that the user comes to the website; assuming the user stays or ever returns to your website.
It's better to use Date()
calc instead of setInterval/setTimeout
to count the time.
It's better to use addEventListener
instead of 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);
}
}
来源:https://stackoverflow.com/questions/4307291/js-onunload-event-wont-always-work