When my system goes to hibernate mode, the javascript timer stop the countdown and when it comes back it continue with the countdown.
But my problem is that I'd like the countdown to continue when my system goes to hibernate mode. Is there any solution / workaround to achieve that?
This isn't really a javascript issue.
When you close the lid, your laptop is hibernating, meaning the CPU is switched off and cannot calculate things.
You have three options
1) Make the laptop stay on when closing the lid, or don't close the lid
2) Stop doing timer tasks client side, and instead simply start a timer on the server. Depending on what you are trying to achieve, this may or may not be relevant, but it is the only way to know the user will keep their lid open/browser open/machine on etc.
3) Re-work your code so instead of using a timer that says "wait ten seconds", you instead set it to use absolute times, something like the following (which is vague pseudo-code to demonstrate what I mean, not a working solution)
var targetTime;
var running = false;
startTimer(timeInSeconds)
{
targetTime = now() + timeInSeconds;
running = true;
}
while(running)
{
if(now() > targetTime)
{
doTimerThings();
running = false;
}
}
This will not get the timer precisely right, but will fire as soon as possible after the machine is started again. You can change your logic to suit how you wish to handle this (eg handling things differently if the timer is being fired late)
It won't help if you need to fire the timer at exactly the interval... but that simply isn't possible when the computer is off.
Related
I have a JS/jQuery code as shown below in which in which I want to keep the JS/jQuery code working when the session tab is not active.
The following code perfectly fine in Google Chrome but it doesn't work in Safari.
jQuery(document).ready(function ($) {
let lastActivity = <?php echo time(); ?>; // Line A
let now = <?php echo time(); ?>;
let logoutAfter = 3600; // page will logout after 1800 seconds if there is no activity
let userName = "<?php echo $_SESSION['user_name']; ?>";
let timer = setInterval(function () {
now++;
let delta = now - lastActivity;
console.log(delta); // Line A
if (delta > logoutAfter) {
clearInterval(timer);
//DO AJAX REQUEST TO close.php
$.ajax({
url: "/control/admin.php",
type: 'GET', // GET also fine
data: {action: 'logout', user_name: userName},
success: function (data) {
window.location.href = "admin.php";
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
}
}, 1000); //<-- you can increase it( till <= logoutAfter ) for better performance as suggested by #"Space Coding"
});
The value at Line A doesn't get incremented in Safari when the tab is not active but it works perfectly fine in Google Chrome. In Google Chrome, it works as expected.
You can replace counter (it counts seconds) with calculating time difference.
let lastActivity = new Date();
let logoutAfter = 3600;
...
let delta = (new Date()).getTime() - lastActivity.getTime();
if (delta > logoutAfter) {
...
}
P.S. So it must work even if the script itself is frozen when tab is inactive. Interval handler will be called at the moment when user activate this tab.
This approach will not work properly with multiple tabs opened. If user open new tab and started working in it, the earlier tab will logout the user as he is not active in that tab.
To overcome this, I will suggest to check the last active time from server using ajax call instead of doing it with javascript only.
According to this very thorough (but old) answer, setInterval() execution on inactive tabs is limited to max 1/s, on both Safari and Chrome - but not stopped. There are also plenty of questions here on SO about Javascript getting paused or de-prioritised on inactive tabs, some of which include solutions:
How can I make setInterval also work when a tab is inactive in Chrome?
iOS 5 pauses JavaScript when tab is not active
Safari JavaScript setTimeout stops when minimized
Chrome: timeouts/interval suspended in background tabs?
Probably the best option to do what you are trying is to use Web workers:
Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface.
There is an example of how to do that in an answer to one of the questions above.
But there is also a much simpler option, though you should evaluate if it is safe considering you are relying on this to log users out.
My testing of your code reflects the question I linked to earlier which describes setInterval() being slowed, but not stopped. For me, Safari (v 13.1, macOS 10.14.6) does not actually fully pause Javascript, but slows down execution of the loop, by increasing amounts. I see this by opening the dev console, and watching the output of the console.log(delta) messages - they slow right down, first running only every 2s, then 4s, and so on, though sometimes faster. But they do not stop.
That output also gives a hint about the problem, and the solution. The delta values shown on the console do not represent the real time difference since lastActivity. They are just incrementing numbers. If you see a delta value appear on the console 10 seconds after the last one, it should logically be +10, right? But it is not, it is just one higher.
And that's the problem here - the code is not counting the true time difference, it is just counting iterations of the loop:
let timer = setInterval(function () {
now++; // <-- problem
This code correctly sets now to the current time only if setInterval() runs exactly every second. But we know that when the tab is inactive, it does not. In that case it is just counting the number of times the loop runs, which has no relation to the real time elapsed.
To solve this problem, we have to determine now based on the real time. To do that, let's switch to using JS to calculate our timestamps (PHP is rendered only once, on page load, so if you use it inside the loop it will just stay fixed at the initial value):
// Note that JS gives us milliseconds, not seconds
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function () {
// PHP won't work, time() is rendered only once, on page load
// let now = <?php echo time(); ?>;
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
Now, even if there is a pause of 10s between iterations, delta will be the true measure of time elapsed since the page was loaded. So even if the user switches away to another tab, every time the loop runs, it will correctly track time, even if it doesn't happen every second.
So what does this mean in your case?
According to your report, JS is not running at all in the inactive tab. In that case, it can happen that the tab stays in the logged-in state, long past the time the user should have been logged out. However, assuming JS starts up again when you switch back the tab, the very first iteration of the loop will correctly calculate the time elapsed. If it is greater than your logout period, you will be logged out. So even though the tab stayed logged in longer than it should have, the user can't use it, since as soon as they switch to it they will be logged out. Note that "as soon" actually means "within 1 second plus the time it takes for the AJAX query to successfully log the user out".
In my testing, JS does not stop in an inactive Safari tab, but slows right down. In this case, it would mean that the user would be automatically logged out on the inactive tab, though not right at the time they should be. If the loop runs say every 8s, it could mean that the user would be logged out up to 7s later than they should have been. If iterations slow down even more, the delay can potentially be even more. Assuming JS starts up again as normal as soon as the user switches back the tab, behaviour will be exactly as above, the first iteration in that case will log them out.
EDIT
Here's simplified, complete code, and a JSFiddle showing it running and working.
jQuery(document).ready(function($) {
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function() {
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
if (delta > logoutAfter) {
alert('logout!');
}
}, 1000);
});
I am creating a music sequencing app and I used the methodology explained in this article. However when I play my project in Chrome all is fine, when I use Firefox the timing is erratic and semi analogous to using setTimeout or SetInterval stand alone.
My scheduler code is below. The JS file can be viewed here. The working app can be viewed by going to the same link as the js file and replacing "javascript/index.js" with "index.html" ( Stackoverflow won't let me post that url directly ).
A JSfiddle is available here
If you listen in Chrome and then Firefox you can hear the difference, the latter is not good. I am not sure if this is my fault or just the way Firefox is.
function scheduleFutureNote() {
while (futureNote <= audioContext.currentTime + 0.10) { //_________When you've gotten within a Nth of a second is when you schedule the note
playFutureNote(futureNote);
futureNote += (60 / tempo) / 4;
}
if (timer) {
timer = window.setTimeout(scheduleFutureNote, 0.10); //__________sleep for n milliseconds...then check to see if we're close to next note.
} else {
timer === false
}
};
window.setTimeout() is in MILLISECONDS, not seconds. You need to setTimeout( scheduleFutureNode, 100).
I'm working on a thick client application which uses JavaScript and jQuery. My Session times out if it's left idle for 45 seconds or more (depending on different business/user).
Currently the timeout event is triggered by the vendor code to which I do not have access. I would like to display a timer on the screen if the session is found to be idle beyond a specific time threshold (for example: 25 seconds).
At the same time the timer should also match (marginal diff can be managed) with the third party timer (to which I do not have access).
Can someone suggest the best solution for this?
It's worth sharing any code you already have so that we can offer more precise advise for you.
However, to give you some pointers, take a look at the JavaScript window.setTimeout() method. It essentially triggers a callback after a set period of time. It's fairly safe to say that if your vendor is using JavaScript to keep track of time, then this is the same basic method they will be using too.
You can set and reset a timeout very easily so once set, you could listen for user interaction events (scrolling, clicking, etc) and use these to trigger a reset on the timeout (putting the 'count down' back to the start).
Do a bit of research, I'm sure you'll be able to develop a suitable solution!
With regards to interfacing with your vendor's timeout, without much more information none of us will be able to help. It doesn't sound like you have any control over this so it may not be possible (perhaps contact the vendor and ask?).
If you know what the timeout limits are for each use-case, you could ensure that your timeouts match theirs. However, this would be a little bit annoying given it's code-repetition and would also mean your application would 'break' if your vendor changes their timings.
TL/DR: Read into the JavaScript window.setTimeout() method if you want to write something that will do what you describe. However, the weak link will be that you don't have access to your vendor's timeout routines. With that in mind, my first step would be to contact the vendor and ask, they may have something in their API already available that you're unaware of!
Okay I don't quite get your logic, but a simple search on Google for jQuery plugin timer gives me:
http://www.tripwiremagazine.com/2013/04/jquery-countdown-scripts.html
A lot...
Hope one of them suits your needs.
Halo,
I finally managed to try a timer in my application (touch based). The following code works well for me.
var count = 50;
$(document).ready(function () {
var Timer = $.timer(function() {
$('#counter').html("Your Session will expire in " + --count + "seconds");
});
Timer.set({ time : 1000, autostart : true });
$(this).mousemove(function (e) {
idleTime = 0;
count = 50;
Timer.reset();
Timer.stop();
});
$(this).keypress(function (e) {
idleTime = 0;
count = 50;
Timer.stop();
Timer.reset();
});
var idleInterval = setInterval(function (){
idleTime = idleTime + 1;
if (idleTime > 10)
{
Timer.set({ time : 600, autostart : true });
$('#counter').css("display", "block");
Morning all, I'm looking for some kind of Javascript event I can use to detect when a mobile browser window regains focus, after either a user closes/minimizes their browser (to go back to a home screen/different app), or if the device resumes from sleep (either the user powering it off, or it going to sleep after a screen timeout).
I'd like to be able to find a single event that works for everything, but I know that's unlikely! The pageshow event works for iOS devices, but it's rather sketchy for use with everything else. I've tried focus and DOMActivate but neither of them seem to have the desired effect.
The page may not always have form elements on it, and I don't really want the user to have to touch the page again to trigger the event.
The requirement for such an event is caused by our code periodically checking for new content by making XHR requests. These are never sent when the browser is asleep, so we never get new content to restart the timeouts.
Thanks for any help you guys may be able to provide!
We had a similar issue and solved it something like this:
var lastSync = 0;
var syncInterval = 60000; //sync every minute
function syncPage() {
lastSync = new Date().getTime(); //set last sync to be now
updatePage(); //do your stuff
}
setInterval(function() {
var now = new Date().getTime();
if ((now - lastSync) > syncInterval ) {
syncPage();
}
}, 5000); //check every 5 seconds whether a minute has passed since last sync
This way you would sync every minute if your page is active, and if you put your browser in idle mode for over a minute, at most 5 seconds will pass before you sync upon opening the browser again. Short intervals might drain the battery more than you would like, so keep that in mind when adapting the timings to you needs.
Better than an interval would be to add a window blur listener and a window focus listener. On blur, record current time. On focus, validate you are still logged in / sync'd / whatever you need to do.
Basically exactly the same thing but it runs only when necessary rather than slowing your entire page down with an interval.
Update
var $window = $(window),
$window.__INACTIVITY_THRESHOLD = 60000;
$window.add(document.body); //necessary for mobile browsers
$window.declareActivity = function () { $window.__lastEvent = new Date(); };
$window.blur($window.declareActivity);
$window.focus(function(){
var diff = (new Date()) - $window.__lastEvent;
if (diff > $window.__INACTIVITY_THRESHOLD) {
$window.trigger("inactivity");
}
});
$window.on("inactivity", "", null, function () {
//your inactivity code
});
Though that blur event seems sketchy if the phone is powering off and I don't know that I would trust it in all circumstances / mobile devices. So I'd probably throw in something like this:
$(document.body).on("click scroll keyup", "", null, $window.declareActivity);
so that my inactivity timer works for when the user just walks away as well. Depending on your site, you may want to adjust that exact event list - or simply throw in a $window.declareActivity(); into your existing scripts that respond to user inputs.
I'm making a webpage with dynamic content that enters the view with AJAX polling. The page JS occasionally downloads updated information and renders it on the page while the user is reading other information. This sort of thing is costly to bandwidth and processing time. I would like to have the polling pause when the page is not being viewed.
I've noticed most of the webpages I have open spend the majority of their time minimized or in a nonviewed tab. I'd like to be able to pause the scripts until the page is actually being viewed.
I have no idea how to do it, and it seems to be trying to break out of the sandbox of the html DOM and reach into the user's system. It may be impossible, if the JS engine has no knowledge of its rendering environment. I've never even seen a different site do this (not that the user is intended to see it...)
So it makes for an interesting question for discussion, I think. How would you write a web app that is CPU heavy to pause when not being used? Giving the user a pause button is not reliable, I'd like it to be automatic.
Your best solution would be something like this:
var inactiveTimer;
var active = true;
function setTimer(){
inactiveTimer = setTimeOut("stopAjaxUpdateFunction()", 120000); //120 seconds
}
setTimer();
document.onmouseover = function() { clearTimeout ( inactiveTimer );
setTimer();
resumeAjaxUpdate();
}; //clear the timer and reset it.
function stopAjaxUpdateFunction(){
//Turn off AJAX update
active = false;
}
function resumeAjaxUpdate(){
if(active == false){
//Turn on AJAX update
active = true;
}else{
//do nothing since we are still active and the AJAX update is still on.
}
}
The stopAjaxUpdateFunction should stop the AJAX update progress.
How about setting an "inactivity timeout" which gets reset every time a mouse or keyboard event is received in the DOM? I believe this is how most IM programs decide that you're "away" (though they do it by hooking the input messages at the system-wide level)
I've looked at that problem before for a research project. At the time (2-3 years ago) I did not find a way to get information from the browser about whether or not you are minimized :(
First check when the window loses and gains focus.
window.onblur = function () { /* stop */ };
window.onfocus = function () { /* start */ };
Also, for various reasons, the user may stop reading the page without causing it to lose focus (e.g. he gets up and walks away from the computer). In that case, you have to assume after a period of inactivity (no mouse or keyboard events) that the users' attention has left the page. The code to do that is described in another answer.
I know you've already accepted an answer but I'd personally use a combination of several of the answers mentioned here for various reasons, including:
Using mouse events only alienates users proficient at keyboard based browsing.
Using blur/focus events don't allow for users who go make a cup of tea ;-)
I'd most likely use something like the following as a guideline:
var idleTimer, userIsIdle, pollingTimer;
document.onkeydown = document.onmousemove = resetTimer;
window.onload = function () {
pollingTimer = window.setTimeout(runPollingFunction, 30000);
resetTimer();
/* IE's onblur/onfocus is buggy */
if (window.navigator.appName == "Microsoft Internet Explorer")
document.onfocusin = resetTimer,
document.onfocusout = setIdle;
else
window.onfocus = resetTimer,
window.onblur = setIdle;
}
function resetTimer() {
if (userIsIdle)
setBack();
window.clearTimeout(idleTimer);
idleTimer = window.setTimeout(setIdle, 120000); // 2 minutes of no activity
}
function setIdle() {
userIsIdle = true;
window.clearTimeout(pollingTimer); // Clear the timer that initiates polling
window.clearTimeout(setIdle);
}
function setBack() {
userIsIdle = false;
runPollingFunction(); // call the polling function to instantly update page
pollingTimer = window.setTimeout(runPollingFunction, 300000);
}
You can listen for mousemove and keypress events. If one of those has been fired in the past X seconds, then continue with your updating. Otherwise, don't update.
It's not perfect, but I think it's the best you can do with pure JS.
If you want to venture into the world of Flash, Silverlight, or Java, you may be able to get more information from the browser.