I'm trying to create a simple interval but it's working slower than expected. I should see message every 100ms but instead I see it every 1 second or so. I just don't see what's wrong with the following code:
var readyWaitElapsed = 0;
var readyWait = window.setInterval(function(){
readyWaitElapsed += 100;
console.log("Elapsed value", readyWaitElapsed);
if (readyWaitElapsed >= 1000){
clearInterval(readyWait);
console.log("Timeout !");
}
}, 100);
When I paste it to the Chrome console I only see "Elapsed value"-message every 1 seconds or so and the clearInterval() "timeout" takes at least 10 seconds to finish.
Does anyone have any idea?
Turns out I was running the code on an inactive tab while the console was active. Apparently when a tab is not active (not in focus) at least Chrome slows down interval and timeout execution to save resources.
This slowdown doesn't seem to be very accurately fixed to any value so it can't be relied either.
Related
I was testing the accuracy of setTimeout using this test. Now I noticed that (as expected) setTimeout is not very accurate but for most appliances not dramatically inaccurate. Now if I run the test in Chrome and let it run in a background tab (so, switching to another tab and browse on there), returning to the test and inspecting the results (if the test finished) they are dramatically changed. It looks like the timeouts have been running a lot slower. Tested in FF4 or IE9 this didn't occur.
So it looks like Chrome suspends or at least slows down javascript execution in a tab that has no focus. Couldn't find much on the internet on the subject. It would mean that we can't run background tasks, like for example checking periodically on a server using XHR calls and setInterval (I suspect to see the same behavior for setInterval, will write a test if time is with me).
Has anyone encountered this? Would there be a workaround for this suspension/slowing down? Would you call it a bug and should I file it as such?
I recently asked about this and it is behaviour by design. When a tab is inactive, only at a maximum of once per second the function is called. Here is the code change.
Perhaps this will help:
How can I make setInterval also work when a tab is inactive in Chrome?
TL;DR: use Web Workers.
There is a solution to use Web Workers, because they run in separate process and are not slowed down
I've written a tiny script that can be used without changes to your code - it simply overrides functions setTimeout, clearTimeout, setInterval, clearInterval
Just include it before all your code
http://github.com/turuslan/HackTimer
Playing an empty sound forces the browser to retain the performance. I discovered it after reading this comment: How to make JavaScript run at normal speed in Chrome even when tab is not active?
With the source of that comment found here:
The Chromium insider also clarified that aggressive throttling will be automatically disabled for all background tabs “playing audio” as well as for any page where an “active websocket connection is present.”
I need unlimited performance on-demand for a browser game that uses WebSockets, so I know from experience that using WebSockets doesn't ensure unlimited performance, but from tests, playing an audio file seems to ensure it
Here's two empty audio loops I created for this purpose, you can use them freely, commercially:
http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg
http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav
(They include -58db noise, -60db doesn't work)
I play them, on user-demand, with Howler.js: https://github.com/goldfire/howler.js
function performance_trick()
{
if(sounds.empty) return sounds.empty.play();
sounds.empty = new Howl({
src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
volume:0.5,
autoplay: true, loop: true,
});
}
It's sad that there is no built-in method to turn full JavaScript performance on/off by default, yet, crypto miners can hijack all your computing threads using Web Workers without any prompt.
I have released worker-interval npm package which setInterval and clearInterval implementation with using Web-Workers to keep up and running on inactive tabs for Chrome, Firefox and IE.
Most of the modern browsers (Chrome, Firefox and IE), intervals (window timers) are clamped to fire no more often than once per second in inactive tabs.
You can find more information on
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals
For unit tests you can run your chrome/chromium with argument: --disable-background-timer-throttling
I updated my jQuery core to 1.9.1, and it solved the Interval discrepancy in inactive tabs. I would try that first, then look into other code override options.
here is my solution which gets the current millisecond, and compares it to the millisecond that the function was created. for interval, it will update the millisecond when it runs the function. you can also grab the interval/timeout by an id.
<script>
var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];
function getCurrentMillis(){
var d = new Date();
var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
return now;
}
function setAccurateTimeout(callbackfunction, millis, id=0){
nowMillisTimeout[id] = getCurrentMillis();
timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}
function setAccurateInterval(callbackfunction, millis, id=0){
nowMillisInterval[id] = getCurrentMillis();
interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}
//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);
setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);
</script>
As part of my react app, I have some setTimeout method to run timer and if that reached zero there is prompt will be pops up, which is working fine as long as the browser in in active state, suppose when we switch between one browser tab to another, I had a issue in delay of execution of this setTimeout intervals, it takes more time to reach zero than the configured one or the initial value that we setting.
Let's say timeoutInterval is 120 seconds as default value, then if we switch another tab this setInterval execution latency issue occured. any solution for this ?
Below is my setInterval method to execute timer.
const [inactiveTimer, setInactiveTimer] = useState(120);
useEffect(() => {
const inactiveInterval = setInterval(() => {
if (timeoutInterval > 0) {
setInactiveTimer(timeoutInterval - 1);
} else if (timeoutInterval === 0) {
setShowModal(true);
}
}, 1000);
return () => {
clearInterval(inactiveInterval);
};
}, []);
When a tab is not active, the function can be called at a maximum of one per second. One option to solve this is to use Web Workers, because they run in separate process, hence are not slowed down.
Another option to solve this issue you can a hack by playing an ~empty sound which will force the browser to keep the regular performance.
More about this inactivation issue - https://codereview.chromium.org/6577021
Empty sound hack - How to make JavaScript run at normal speed in Chrome even when tab is not active?
I was testing the accuracy of setTimeout using this test. Now I noticed that (as expected) setTimeout is not very accurate but for most appliances not dramatically inaccurate. Now if I run the test in Chrome and let it run in a background tab (so, switching to another tab and browse on there), returning to the test and inspecting the results (if the test finished) they are dramatically changed. It looks like the timeouts have been running a lot slower. Tested in FF4 or IE9 this didn't occur.
So it looks like Chrome suspends or at least slows down javascript execution in a tab that has no focus. Couldn't find much on the internet on the subject. It would mean that we can't run background tasks, like for example checking periodically on a server using XHR calls and setInterval (I suspect to see the same behavior for setInterval, will write a test if time is with me).
Has anyone encountered this? Would there be a workaround for this suspension/slowing down? Would you call it a bug and should I file it as such?
I recently asked about this and it is behaviour by design. When a tab is inactive, only at a maximum of once per second the function is called. Here is the code change.
Perhaps this will help:
How can I make setInterval also work when a tab is inactive in Chrome?
TL;DR: use Web Workers.
There is a solution to use Web Workers, because they run in separate process and are not slowed down
I've written a tiny script that can be used without changes to your code - it simply overrides functions setTimeout, clearTimeout, setInterval, clearInterval
Just include it before all your code
http://github.com/turuslan/HackTimer
Playing an empty sound forces the browser to retain the performance. I discovered it after reading this comment: How to make JavaScript run at normal speed in Chrome even when tab is not active?
With the source of that comment found here:
The Chromium insider also clarified that aggressive throttling will be automatically disabled for all background tabs “playing audio” as well as for any page where an “active websocket connection is present.”
I need unlimited performance on-demand for a browser game that uses WebSockets, so I know from experience that using WebSockets doesn't ensure unlimited performance, but from tests, playing an audio file seems to ensure it
Here's two empty audio loops I created for this purpose, you can use them freely, commercially:
http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg
http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav
(They include -58db noise, -60db doesn't work)
I play them, on user-demand, with Howler.js: https://github.com/goldfire/howler.js
function performance_trick()
{
if(sounds.empty) return sounds.empty.play();
sounds.empty = new Howl({
src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
volume:0.5,
autoplay: true, loop: true,
});
}
It's sad that there is no built-in method to turn full JavaScript performance on/off by default, yet, crypto miners can hijack all your computing threads using Web Workers without any prompt.
I have released worker-interval npm package which setInterval and clearInterval implementation with using Web-Workers to keep up and running on inactive tabs for Chrome, Firefox and IE.
Most of the modern browsers (Chrome, Firefox and IE), intervals (window timers) are clamped to fire no more often than once per second in inactive tabs.
You can find more information on
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Timeouts_and_intervals
For unit tests you can run your chrome/chromium with argument: --disable-background-timer-throttling
I updated my jQuery core to 1.9.1, and it solved the Interval discrepancy in inactive tabs. I would try that first, then look into other code override options.
here is my solution which gets the current millisecond, and compares it to the millisecond that the function was created. for interval, it will update the millisecond when it runs the function. you can also grab the interval/timeout by an id.
<script>
var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];
function getCurrentMillis(){
var d = new Date();
var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
return now;
}
function setAccurateTimeout(callbackfunction, millis, id=0){
nowMillisTimeout[id] = getCurrentMillis();
timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}
function setAccurateInterval(callbackfunction, millis, id=0){
nowMillisInterval[id] = getCurrentMillis();
interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}
//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);
setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);
</script>
I am currently doing some fun website, which requires audio cues (I assume that's the name?). I want the site to do something, when the song has been played for exactly X amount of time.
I can easily get the current time using element.currentTime, but I have no clue how to say: when element.currentTime == 5.2, runFunction() - If you know what I mean. Is there some kind of way this could be done? My current test code:
<----AUDIO WILL START PLAYING---->
http://jsfiddle.net/jfL4mcnh/
$("<audio id='audioElement'>").appendTo("body");
$("#audioElement").attr("src", "http://mp3ornot.com/songs/1B.mp3").attr("autoplay", "autoplay");
setInterval(function() {
//for some reason, $("#audioElement").currentTime won't work, so we're going old fashion
time = document.getElementById("audioElement").currentTime;
console.log(time);
}, 1000);
Also, I forgot to say this, I cannot do a setTimeout() and hit at the exact moment I want in milliseconds, because the audio can take some extra time to load, while the actual code runs exactly when it has been "seen", if you know what I mean. So no countdown. I need to be exact here.
If you need greater resolution than ontimeupdate provides, you can use a setInterval instead.
Live Demo (sound and alert box only!):
$("<audio id='audioElement'>").appendTo("body");
$("#audioElement").attr("src", "http://mp3ornot.com/songs/1B.mp3").attr("autoplay", "autoplay");
var triggered = false;
var ael = document.getElementById("audioElement");
var interval = setInterval(function(){
console.log(ael.currentTime);
if (!triggered && ael.currentTime >= 5.2) {
triggered = true;
alert("5.2 seconds reached");
}
if (ael.ended) clearInterval(interval);
}, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
JSFiddle Version: http://jsfiddle.net/jfL4mcnh/15/
Well, I have done it myself.. It seems.
http://jsfiddle.net/jfL4mcnh/13/
$("#audioElement").bind("timeupdate", function() {
var currentTime = parseInt(this.currentTime, 10);
if(currentTime == 2) {
console.log("2 seconds in");
$(this).unbind("timeupdate");
}
});
You can bind timeupdate to it, then unbind it (apparently it runs the code 4 times, so I have to unbind it).
EDIT: Nope, it doesn't update fast enough to make it perfect on point. It increments each ~300ms it seems.
See this jsfiddle here
I've added the following line to the JavaScript setInterval() function:
if (time > 5.2) {
myFunction();
}
myFunction() does a console.log, which you'll see in the console.
The reason I used > rather than === is that the time reported is never precise due to fluctuations in processing. A Boolean in the condition would solve this problem:
triggered = false;
if (time > 5.2 && !triggered) {
triggered = true;
myFunction();
}
I am working on an application that sends current timestamp to database every 2 minutes with AJAX using setInterval.
But somehow setInterval stops after some minutes (i didnt calculate the exact time), but i believe it happens when i dont open that browser's tab for 20-30 minutes.
function tmstmp() {
$.post("send_functions.php?act=time");
}
$(function() {
setInterval(tmstmp, 60000);
});
Is that normal that setInterval stops if that tab is not on foreground ?
If yes, how can i prevent setInterval to stop ? or check if it stopped ?
Thanks
You should try to make an function call on page startup:
test();
and then loop that function:
function test() {
setTimeout(function() {
// your code
test();
}, 2000);
}
That's not supposed to happen.
Browsers may indeed reduce the timer resolution to something around 1/s, but not clear the setInterval.
Could there be some bug in your code that causes a clearInterval?
No code + no debug information = hard to tell what went wrong.
Just to be sure add the following line to the code (method) that gets executed with setInterval and watch after 20-30 minutes if you still get output in the console.
console.log('Yep! I am alive!');
EDIT: Could be anything but try changing the tmstmp method to include a callback function after the POST request gets executed. That way you'll at least know that it works.
function tmstmp() {
$.post("send_functions.php?act=time", function(data){
console.log('Yep! I am alive!');
});
}