I have a background script that uses the setInterval command to do a network request on a routine basis.
I was wondering if the background script can detect if the os goes on sleep or standby so that I can adjust the timer displayed upon resuming the background script. I understand that the setInterval timer is suspended during sleep based on this Answer: What happens to setTimeout when the computer goes to sleep?
Code sample is background.js
set_start_time();
search_set_int = setInterval(function() {
foo();
// Set the Auto Search Start time for the next run
set_start_time();
}, frequency); // Set interval function
var total_time_left_sec = (frequency/1000) - (current_time_unix - start_time_unix)
Thanks
Keep a local variable with the timestamp of the last interval run.
On normal (no sleep) execution, the timestamp will be about now-period, but on sleep it will be older so you know you come from a sleep.
Also do not rely on the interval as your 'tick' for calculating elapsed time
Instead remember the starting timestamp and substract from now()
Related
I'm using MIDI.js to play a MIDI file with several musical instruments.
The following things execute too late, how can I fix that?
First notes of the song. Like all notes, they are scheduled via start() of an AudioBufferSourceNode here.
MIDI program change events. They are scheduled via setTimeout here. Their "lateness" is even worse than that of the first notes.
When I stop the song and start it again, there are no problems anymore, but the delay values are very similar. So the delay values are probably not the cause of the problem.
(I use the latest official branch (named "abcjs") because the "master" branch is older and has more problems with such MIDI files.)
That is how JavaScript Event Loop works.
Calling setTimeout ... doesn't execute the callback function after the given interval.
The execution depends on the number of waiting tasks in the queue.
... the delay is the minimum time required for the runtime to process the request (not a guaranteed time).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#zero_delays
Instead of setTimeout() you can use window.requestAnimationFrame() and calculate elapsed time for delay by yourself.
Window.requestAnimationFrame() - Web APIs | MDN
The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.
... will request that your animation function be called before the browser performs the next repaint. The number of callbacks is usually 60 times per second, but will generally match the display refresh rate in most web browsers
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
performance.now() - Web APIs | MDN
https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
In our situation, we don't want to do any animation but want to just use it for a better-precision timeout.
const delayMs = 1000;
const startTime = performance.now();
function delay(func) {
const delayStartTime = performance.now();
function delayStep() {
// Run again if still elapsed time is less than a delay
if (performance.now() - delayStartTime <= delayMs) {
window.requestAnimationFrame(delayStep);
}
else
{
// Run the delayed function
func();
}
}
// Run first time
window.requestAnimationFrame(delayStep);
}
// Trying `setTimeout()`
setTimeout(() => doSomeJob('setTimeout()'), delayMs);
// Trying `delay()`
delay(() => doSomeJob('delay()'));
// Function that we'd like to run with a delay
function doSomeJob(marker)
{
const elapsedTime = performance.now() - startTime;
console.log(`${marker}: Ran after ${elapsedTime / 1000} seconds`);
}
If you run it many times, you'll see that delay() is pretty much all the time better than setTimeout(). The difference is very small because there is nothing else happens on the page. If there will be something intensive running, setTimeout() should demonstrate worse "precision".
I'm building a live chess app, and I'm trying to add a timer to it. However, I am struggling to find a way to make the timer accurate. I have run some tests, and setInterval and setTimeout are extremely inaccurate, with a ten minute timeout being off by over three minutes. I also tried using setInterval with in interval of 100ms, but even that was off by over minute, when the tab was not active. That was just with the javascript window.setInterval; with nodejs, it hasn't been more than 10ms off, but I'm afraid it will if the server gets busy. I'm hoping to find a way to have the game end within at least a tenth of a second of the real time.
Any suggestions? Thanks!
an ideal approach would be to use absolute clock time to get time elapsed and timer to have that check.
Something like code below.
const startTime = new Date();
const maxTime = 5 * 1000; // 60 seconds
setInterval(() => {
checkExpired();
}, 300);
function checkExpired() {
const curTime = new Date();
timeDifference = Math.abs(curTime.getTime() - startTime.getTime());
if (timeDifference > maxTime) {
console.log("time up");
}
}
The browser will not run setInterval as required due to performance reason.
https://usefulangle.com/post/280/settimeout-setinterval-on-inactive-tab
If you need to run timer with required interval then it can be run in worker thread.
some info here.
How can I make setInterval also work when a tab is inactive in Chrome?
But my guess is increased granularity is fine for non active tab.
My ionic app has a timer(a simple setInterval that ticks every second) which works perfectly fine when the app is in the foreground. However when the app goes to the background and comes back to the foreground after 10 minutes, the time displayed in the app is wrong (the time is much less that it should be). I have tried adding the timer into a directive and also using the native DOM manipulation api(document.getElementById, etc) methods, but they both didn't work. I think the ionic framework is doing something to the view and bindings when the app goes to the background. Has anyone experience such a issue and if so how did you guys manage to fix it?
After hours of searching for an answer, I finally came up with my own hack. I hope this solution might help others who come across a similar issue.
When the app goes to the background, at some random time, the timer stops ticking and goes to sleep till the app is brought back the foreground.
When the app comes up to the foreground, the timer starts ticking again from the point where it went to sleep.
Solution/Hack:
Record the timestamp in a separate variable(in seconds) and have it updated in each interval of the timer.
var timeStamp = Math.floor(Date.now() / 1000);
Check each interval of the timer if the difference between your previous interval's timeStamp and the latest(new) timeStamp is greater than one second. If the condition is met, add the difference between those two timestamps to your ticking time.
How it works:
App in Foreground
Just Before timer start ticking
- Time stamp recorded (Assume 1 second)
Timers start ticking
- check condition
if(currentTimeStamp - previousTimeStamp > 1)
{
Add the the above difference to the time
}
Before the interval ends, update the TimeStamp variable with the currentTimeStamp.
In the first interval, the currentTimeStamp should be either 1 second or 2 second depending on weather you are offloading the timer into a setTimeout.
Thus the difference will definitely be 0 or 1. Since the condition doesn't match we update the timestamp with 1 or 2 seconds and move on to the next interval.
As long as the timer doesn't go to sleep our condition will fail.
App in Background
Strangely after 10 minutes, the timer goes to sleep(our timer is literally losing track of time from now because the next interval is not firing).
App return from Background to foreground
The timer starts ticking from where it stopped(i.e. the next interval). Now the difference in our condition should be more than one second and thus adding that difference(basically the lost time) to our current ticking time.
Code:
var transactionTime = 0; //Initial time of timer
var timeStamp = Math.floor(Date.now() / 1000);
var deltaDelay = 1;
setInterval(function () {
if (transactionTime != 0 && (Math.floor(Date.now() / 1000) - timeStamp) > deltaDelay) {
transactionTime += (Math.floor(Date.now() / 1000) - timeStamp);
}
timeStamp = Math.floor(Date.now() / 1000);
//Update your element with the new time.
window.document.getElementById("transaction_timer").innerHTML = util.formatIntoHHMMSS(transactionTime++);
}, 1000);
Note: This solution work standalone(vanilla Js with native DOM api) and also works great in angular directives.
You can increase the deltaTime of the above code to 2 to be a little more accurate if by any chance your single thread is busy somewhere else with some other task.
P.s I'm actually running the ionic app inside my own instance of a webview and not cordova so I can't use any fancy cordova plugin.
Ionic/Cordova apps goes to sleep when in background mode. But you could look at this: https://github.com/katzer/cordova-plugin-background-mode
Here is a little bit updated code from the
original answer
var interval = null;
var timerSecondsTotal = 0;
function runTimer() {
var prevTickTimestamp = Date.now()
interval = setInterval(() => {
var currentTickTimestamp = Date.now()
var delta = currentTickTimestamp - prevTickTimestamp
timerSecondsTotal += Math.round(delta / 1000)
prevTickTimestamp = currentTickTimestamp
}, 1000)
}
In my aspx page, I use xmlhttp.response to update a part of this page. This update occurs in every 3 seconds using js function. But when my PC goes to sleep mode, this update doesn't happen. This is OK. But when PC wake up from sleep mode, I need to start update automatically without reload this page. How to do this?
You can detect disruptions in the JS timeline (e.g. laptop sleep, alert windows that block JS excecution, debugger statements that open the debugger) by comparing change in wall time to expected timer delay. For example:
var SAMPLE_RATE = 3000; // 3 seconds
var lastSample = Date.now();
function sample() {
if (Date.now() - lastSample >= SAMPLE_RATE * 2) {
// Code here will only run if the timer is delayed by more 2X the sample rate
// (e.g. if the laptop sleeps for more than 3-6 seconds)
}
lastSample = Date.now();
setTimeout(sample, SAMPLE_RATE);
}
sample();
In a modern web browser, suppose I do a setTimeout for 10 minutes (at 12:00), and 5 minutes later put the computer to sleep, what should happen when the system wakes up again? What happens if it wakes up before the 10 minutes are up (at 12:09) or much later (at 16:00)?
The reason I'm asking is because I'd like to have a new authentication token requested every 10 minutes, and I'm not sure if the browser will do the right thing and immediately request a new token if it wakes up after a long time.
Clarifications: I don't wan't to use cookies - I'm trying to build a web service here; and yes, the server will reject old and invalid tokens.
As far as I've tested, it just stops and resumes after the computer wakes up. When the computer awakes the setInterval/setTimeout is unaware that any time passed.
I don't think you should rely on the accuracy of setTimeout/Interval for time critical stuff. For google chrome I discovered recently that any timeout/interval (that is shorter than 1s) will be slowed down to once a second if the tab where it's activated looses focus.
Apart from that the accuracy of timeouts/intervals is dependent on other functions running etc. In short: it's not very accurate.
So using interval and timeouts, checking the time against a starttime within the function started by it would give you better accuracy. Now if you start at 12:00, the computer goes to sleep and wakes up at 16:13 or so, checking 16:13 against 12:00 you are certain you have to renew the token. An example of using time comparison can be found here
Compare current datetime against datetime when the page was loaded, like so:
//Force refresh after x minutes.
var initialTime = new Date();
var checkSessionTimeout = function () {
var minutes = Math.abs((initialTime - new Date()) / 1000 / 60);
if (minutes > 20) {
setInterval(function () { location.href = 'Audit.aspx' }, 5000)
}
};
setInterval(checkSessionTimeout, 1000);
Here is my code :
<!doctype html>
<html>
<body>
<input type="button" name="clickMe" id="colourButton" value="Start Timer" onclick="setTimeout('alert(\'Surprise!\')', 120000)"/>
</body>
<script>
</script>
</html>
I have taken three scenarios that might answer the question.
Scenario 1: At 00 Seconds click on 'Start Timer' button . At 25 seconds computer falls asleep.
At 1min 40 seconds wake up computer.
At 2mins Alert is displayed.
Scenario 2 : At 00 Seconds click on 'Start Timer' button . At 26 seconds computer falls asleep.
At 3 mins, I wakeup the computer. The Alert is displayed.
Scenario 3 : This one is truly astounding.
<input type="button" name="clickMe" id="colourButton" value="Start Timer" onclick="setTimeout('alert(\'Surprise!\')', 600000)"/>
At 00 Seconds I click on 'Start Timer' button.
At around 1min 30 seconds the computer is on hibernate mode (my pc takes a minute to initiate hibernate)
At 8 mins I turn the laptop on.
At 10 mins exactly, the alert pops up.
PS: This is my first ever comment on Stack Exchange. I prefer to execute code and view results rather than infer from theory.
The behavior is based on both the browser and the operating system. The OS handle sleep and individual apps often don't account for it.
What will most likely happen is that the OS will come back up with the same time remaining on the timer as when it was shut down. The other possibility is that it won't fire at all.
If it is really a concern, you will probably want to be better safe than sorry and store a time stamp of when the token was initialized and use setInterval to check it periodically (say twice a minute).
However, security should not be just a client side thing. Make sure that your server throws an error if an old / invalid token is used and that the Ajax behaves appropriately in response.
[edit]
I agree with the other post that it might fire immediately on the next tick. Resig's blog post is very good.
Behaviour of JavaScript timers (setTimeout) in several scenarios.
When the thread is free and the timeout fires: The timer is fired immediately after the timeout. It might have certain imprecision of about 0-5 ms (typical scenario).
When the thread is super busy (huge loop) long enough to pass the timer timeout: The timer will be executed immediately after the thread is freed.
When there is an alert: Same behaviour as 2.
When the thread is paused because our laptop went to sleep: I have seen several things. But most common is total inaccuracy and ignore of the time spent during sleeping.
Since timers in JavaScript are based on CPU ticks, and the CPU is sleeping, then the timer is completely paused and resumed as 'since nothing would have happen'.
Based on Ben's answer, I created the following util. You can tweak the sampling duration, however I use it just like this for token refreshing:
const absoluteSetInterval = (handler, timeout) => {
let baseTime = Date.now();
const callHandler = () => {
if (Date.now() - baseTime > timeout) {
baseTime = Date.now();
handler();
}
};
return window.setInterval(callHandler, 1000);
};
const absoluteClearInterval = (handle) => window.clearInterval(handle);
In John Resig's blog the timers are said to be using "wall clock". I believe that the events will fire immediately after the machine is resumed because setTimeout() doesn't guarantee an execution is a specific point in time but as soon as possible after the specified interval. However, I haven't checked it myself.