35 comments

[ 2.8 ms ] story [ 85.8 ms ] thread
Any way to disable this background tab throttling for web apps, or detect its presence and warn users?
> We investigated how background tabs use system resources and found that JavaScript Timers represent >40% of the work in background tabs. ... Beginning in M87, we’re throttling JavaScript timer wake-ups in background tabs to once per minute. This reduces CPU usage by up to 5x, and extends battery life up to 1.25 hours in our internal testing. We’ve done this without sacrificing the background features that users care about, like playing music and getting notifications.
...what in the world are all of those background timers doing? Polling for things like element visibility or something? I rarely have use for timers, especially now that CSS animations are available everywhere
things like this:

    var tid = setInterval(function() {
        var bef = new Date().getTime();
        debugger ;var af = new Date().getTime();
        if (af - bef > 100) {
            clearInterval(tid);
            window.location.href = "/";
        }
    }, 100);
(Chromium dev here)

Yes, lots of sites are written with tight setInterval/setTimeout loops, checking for modifications to the DOM, visibility, doing animations, etc. In most cases there are modern web APIs that do these things for you that don't require polling (rAF, MutationObserver, IntersectionObserver, etc). Throttling is mostly about reducing the impact of these sites. We are not trying to penalize well-written sites, and if you have valid use cases that you feel are being unfairly penalized we're more than happy to accept feedback!

Thanks for the added context! That makes sense. I've debugged one or two hastily-assembled marketing sites in my time and I've seen some atrocious practices along these lines. At one time you could charitably write it off as maximizing browser support, but much of it can't really be explained that way anymore. It's a shame that sites like these drag down the web experience as a whole.
I wonder if this could cause background tabs to develop a large queue of unprocessed events, thus making the tab unresponsive for a while when switching back to it. I used to see this happen on native apps on macOS with App Nap for a while but it seems better on recent versions of macOS.
I see this with the console at least when developing. You switch back to the tab and the console eats shit and locks up because of the back pressure.
the nice thing with the web is that developers respond reasonably fast (much faster than desktop apps) to changes like this in major browsers...
This a good point. The application does x amount of work per second in the background. Your browser pauses it for y seconds. According to Google you have saved "x times y times energy per operation". Chrome devs say hurray 5x energy savings. Except when you switch back to the tab you end up spending the same amount of energy to catch up.

The primary source of energy savings would be poorly written websites that constantly poll in the background. Games with complicated logic would still consume the same amount of energy.

(Chromium dev here.)

For the most part, events can't really accumulate, because not running code means no new events are posted. The throttling applies to setTimeout/setInterval, and not to any external event (incoming network data, API callbacks, etc).

Sites that legitimately have to do a fixed amount of work per unit time (via timers) will simply do that work with 1 wake-up per minute. All things being equal, this still means less battery usage because energy usage is a function of both wakeups and total CPU usage.

> The primary source of energy savings would be poorly written websites that constantly poll in the background.

This is the key insight here, and really what we're going after. There is a lot of this on the web.

This seems like a good idea because APIs already exist to detect whether a page has been backgrounded, so it should be simple enough for a JS app to cease creating timers when they aren't necessary. (Since I'm guessing a lot of timers get created for the purposes of visual reactivity)

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibi...

I wonder if this would effect Web Workers in the same way.

Does anyone know how to correctly deal with these paused tabs for computing incremental games with timer based events?

It claims that it still ticks timers once a minute for background tabs, but I can measure that it ticks exactly zero times for background tabs (and from now on also for foreground tabs that are occluded...), and in addition may also lie in results of Date.now(). So what does the article even mean by "once per minute"? If I put a tab in background, it immediately stops any tick, if I bring the tab back in the foreground 24 real life hours later, it'll have been 24 real life hours since its last update, not one minute, as I can see by printing events in the console.

That makes it difficult to correctly update how much resources were produced in the game, etc....

You can never rely on the timers firing exactly as you request, so you always have to take the delta since the last timer and use that in your calculations.

This is a very basic issues with doing stuff on a timer, and not that hard to do properly. It shouldn't make a difference if your timer is called once per second, once per minute or once in 10 hours in the background, you always calculate based on the delta to the last time your timer fired.

It can be an issue if the game can do complex actions at any time: if you then need to do all of it in one gigantic update after e.g. 24 hours of being in the background, it may take too long to compute that one long tick. Depending on what type of game it is. If it just has to compute "so many resources per second produced" it's easy of course and you can use the delta between last tick (if Date.now() works correctly), but if the game can auto-build various things with complex interactions, it can become computationally complex if it has to do all at once.
It sounds like the tab throttling is working as intended then. If I've moved from your game and haven't looked at it then why shouldn't all of that extra computation happen until the next time I'm interested?
For idle games, much of the point is investing in auto-building, then coming back to the game when your investment has borne fruit. For this to work, it has to be able to run in the background.
There is a big difference between throttling and not running. Still, it is probably much better to sync with the server than run something at full blast to increment some counters.
Sounds like it's time for the game authors to provide some servers with the compute resources to do this background processing.
(Chromium dev here.)

Doing the work in one giant update is actually better from a power consumption / battery point-of-view, because the CPU cost is fixed but there are fewer wakeups overall.

Note that the new throttling logic means you get woken-up once per minute; we're not talking about preventing your page from doing work for a 24 hour period.

For full details of how the throttling works, see here:

https://www.chromestatus.com/feature/4718288976216064

But if it lies about Date.now() this isn't possible..
That would be broken and isn't what is being talked about here. There is no reason scheduling as a low priority would mean you need to lie about the current time.
That is a very good advice, thank you.
What do the background tabs do with server side events or websockets? You should be able to just open a connection and send a message over WS or have the server drop the connection on every tick. You can probably do it without a server by hitting an address that will blackhole the connection instead of refusing it and use an AbortController [1] to timeout the request.

[1] https://developer.mozilla.org/en-US/docs/Web/API/AbortContro...

The question is mainly about a client-side game, no multiplayer or servers.

Here is some context (just a random thread about the issue, threads like this pop up regularly):

https://www.reddit.com/r/incremental_games/comments/j86u5m/g...

5 years ago such games worked in background tabs. Then browsers started throttling background tabs (for understandable reasons) and everyone learned to keep it in a foreground tab in a window you don't use. Now the latter will also stop working.

I'm tired of too-smart browsers, I want a dumb one.
Do service workers continue running?
Didn't test (yet), but if they do, then what's the point of throttling background tabs?
Service workers have restrictions on what they can do. They can't interact with thr dom and a few other things to keep them from causing rendering or other changes.
(Chromium dev here.)

We don't throttle workers (that could change, but we don't have firm plans here yet).

All things being equal, if you move complex work to workers we're happy because it frees up the main thread to handle input events, compositing, etc. Just because your tab is in the background doesn't mean your renderer process isn't sharing a main thread with a tab that is in the foreground, so in this case it can improve foreground tab performance.

Also, spreading a fixed amount of work across more cores and fewer wake-ups is actually more efficient from a power point of view (assuming the wake-ups are synchronized).

(Chromium dev here.)

Yes, for now all workers continue to run unthrottled (shared, dedicated and service). They may also be throttled at some point, but we have no firm plans around this yet.

Sometimes I put a tab away because I don't want to watch whatever stupid animation it wants to do. When I switch back to the tab later, I want it to be done fucking around. With this change that's not going to work, right?
If you are looking for a way to deal with a multitude of Chrome tabs, I recommend the Chrome extension The Great Suspender, which suspends tabs after x minutes.