Timers methods setTimeout() / setInterval() running on background tabs can be resource exhausting. An application running callbacks at very short intervals in a background tab may drain a lot of memory to the point that the working of the currently active tab may be impacted.
I know I'm coming late but the answer is in Chrome menu (the three stripes): Go to settings -> Show Advanced settings -> Privacy: uncheck the option that says 'Predict network actions to improve page load performance'. Hope that helps.
So the animation isn't running 30 times a second in case the tab is inactive. This can be confirmed by counting the amount of times the setInterval function is called each second - this will not be 30 but just 1 or 2 if the tab is inactive.
Starting with Google Chrome 79, a new Tab Freeze feature has been added that will automatically pause (freeze) tabs when they have been inactive in the background for 5 minutes by default until you return to the tab.
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?
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 2 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
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With