How Do Browsers Pause/Change JavaScript When Tab or Window Is Not Active

How do browsers pause/change Javascript when tab or window is not active?

Test One

I have written a test specifically for this purpose:

Frame Rate Distribution: setInterval vs requestAnimationFrame

Note: This test is quite CPU intensive. requestAnimationFrame is not supported by IE 9- and Opera 12-.

The test logs the actual time it takes for a setInterval and requestAnimationFrame to run in different browsers, and gives you the results in the form of a distribution. You can change the number of milliseconds for setInterval to see how it runs under different settings. setTimeout works similarly to a setInterval with respect to delays. requestAnimationFrame generally defaults to the 60fps depending on the browser. To see what happens when you switch to a different tab or have an inactive window, simply open the page, switch to a different tab and wait for a while. It will continue to log the actual time it takes for these functions in an inactive tab.

Test Two

Another way to test it is to log the timestamp repeatedly with setInterval and requestAnimationFrame and view it in a detached console. You can see how frequently it is updated (or if it is ever updated) when you make the tab or window inactive.

  • Test for setInterval
  • Test for requestAnimationFrame

Results

Chrome
Chrome limits the minimum interval of setInterval to around 1000ms when the tab is inactive. If the interval is higher than 1000ms, it will run at the specified interval. It does not matter if the window is out of focus, the interval is limited only when you switch to a different tab. requestAnimationFrame is paused when the tab is inactive.

// Provides control over the minimum timer interval for background tabs.
const double kBackgroundTabTimerInterval = 1.0;

https://codereview.chromium.org/6546021/patch/1001/2001

Firefox
Similar to Chrome, Firefox limits the minimum interval of setInterval to around 1000ms when the tab (not the window) is inactive. However, requestAnimationFrame runs exponentially slower when the tab is inactive, with each frame taking 1s, 2s, 4s, 8s and so on.

// The default shortest interval/timeout we permit
#define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
#define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms

https://hg.mozilla.org/releases/mozilla-release/file/0bf1cadfb004/dom/base/nsGlobalWindow.cpp#l296

Internet Explorer
IE does not limit the delay in setInterval when the tab is inactive, but it pauses requestAnimationFrame in inactive tabs. It does not matter whether the window is out of focus or not.

Edge
Starting from Edge 14, setInterval is capped at 1000ms in inactive tabs. requestAnimationFrame is always paused in inactive tabs.

Safari
Just like Chrome, Safari caps setInterval at 1000ms when the tab is inactive. requestAnimationFrame is paused as well.

Opera
Since the adoption of the Webkit engine, Opera exhibits the same behavior as Chrome. setInterval is capped at 1000ms and requestAnimationFrame is paused when the tab is inactive.

Summary

Repeating intervals for inactive tabs:


setInterval requestAnimationFrame
Chrome
9- not affected not supported
10 not affected paused
11+ >=1000ms paused

Firefox
3- not affected not supported
4 not affected 1s
5+ >=1000ms 2ns (n = number of frames since inactivity)

IE
9- not affected not supported
10+ not affected paused

Edge
13- not affected paused
14+ >=1000ms paused

Safari
5- not affected not supported
6 not affected paused
7+ >=1000ms paused

Opera
12- not affected not supported
15+ >=1000ms paused

why does current tab pause every time when I switch tabs in browser?

This is a feature of setAnimationFrame at work. Browsers limit the processing on inactive tabs to save power consumption and CPU cycles. For more information: https://stackoverflow.com/a/5927432/7316502

It doesn't make sense to play an animation that people can't see. However, it might make sense to update the position of the creature in the background and display its current position when the user returns to the tab, given its target point and velocity.

If I understand correctly, the desired outcome is to click a point, have the monster start moving, and then when you tab away and tab back, it's as though the monster has moved the same amount as if you were watching.

You could use the Page Visibility API to help do this: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

On a visibilityChange, you can check to see if window.hidden===true. If so, pause the simulation and await another visibilityChange event for which window.hidden===false.

When focus returns to the tab, calculate the time difference between the current time and the time the window became hidden. Fast-forward your rendering to this time point. Then continue displaying animation.

Here is an example of what this might look like.

I placed this in your init() function.

function handleVisibilityChange() {
if (document.hidden) {
windowHidden=true;
hideTime=window.performance.now();
} else {
windowHidden=false;
var timeDiff=(window.performance.now()-hideTime)/1000;
console.log('Page invisible for ',timeDiff,' seconds, jump ahead.');
tick(timeDiff);
render();
}
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);

Then I placed a check in your tick function to check the windowHidden flag:

if (!level||windowHidden) { return; }

(almost-complete) example: https://jsfiddle.net/thmsdnnr/thk80hsh/2/

Note that this does not quite work the way you'd intend: currently the monster just proceeds on the path toward the next node while the window is hidden. This is why when you tab back, the monster is off the path, proceeds back to the last node it was headed toward, and then continues.

Since the monster is following a path with multiple points and different directed segments, you'd need to refactor your tick function, or (better choice, I think) write another one entirely, that takes the time interval the window was hidden for and calculates the number of nodes on the path the monster would have passed given its velocity and time, removes those nodes, and renders the monster in the correct position.

Run a Javascript code on an inactive browser tab every n hours

Finally, I have a solution to my problem in question. I used "visibilityState" event to detect when an inactive tab is clicked, I also had a window scope variable that I used to record the last time when my script had executed(window.globalVar.lastProfileTime). Using both, I introduced this logic:

const lastProfileTime = window.globalVar.lastProfileTime;
if((document.visibilityState === 'visible') &&
((typeof(lastProfileTime) === 'undefined') ||
((currentTime - lastProfileTime) > 86400000))) {
// do something
}

Pause animation when leaving window or entering a new tab, continue animation upon re-entering?

You need to add event listeners to the window itself for the focus and the blur events.

Check this:

http://fiddle.jshell.net/6gdrQ/15



Related Topics



Leave a reply



Submit