How Safari Throttles Background Tabs to Save Battery Life
This article explains how Apple’s Safari web browser extends battery
life on MacBooks and iPhones by aggressively managing background web
activity. By suspending requestAnimationFrame callbacks and
throttling JavaScript timers like setTimeout and
setInterval in hidden or occluded tabs, Safari prevents
unseen web pages from draining system resources. This approach
drastically reduces CPU wake-ups and GPU rendering, translating directly
into longer battery life without degrading the active user
experience.
The Hardware Cost of Unseen Web Pages
Modern websites rely heavily on JavaScript to update content, track analytics, and render smooth animations. When a tab is actively viewed, the device's processor (CPU) and graphics chip (GPU) work constantly to execute this code.
However, if a user has twenty tabs open, nineteen of them are not being viewed. If Safari allowed all twenty tabs to run animations at 60 or 120 frames per second and execute millisecond-level timers, the CPU would never enter a low-power idle state. To prevent this energy waste, Safari’s underlying engine, WebKit, changes how it executes code the moment a tab is no longer visible.
Suspending
requestAnimationFrame
The requestAnimationFrame API is used by web developers
to create smooth visual animations. In an active Safari tab, this method
tells the browser to execute a specific block of JavaScript code right
before the screen repaints—usually 60 times per second (every 16.6
milliseconds) on standard displays, or 120 times per second on ProMotion
displays.
When you switch to a different tab, minimize the browser, or cover the Safari window, those animations are no longer visible. Rendering them wastes GPU and CPU power.
Safari handles this by completely suspending
requestAnimationFrame in background tabs. Rather than
slowing the animations down, WebKit stops firing the callback entirely.
As soon as the tab becomes visible again, Safari resumes the
requestAnimationFrame loop from where it left off.
Throttling
setTimeout and setInterval
Unlike animation frames, standard JavaScript timers—specifically
setTimeout and setInterval—cannot always be
completely paused without breaking website functionality, such as chat
notifications or background data syncing. Instead of stopping them,
Safari throttles and coalesces them.
In an active tab, Safari allows nested timers to run as fast as once every 4 milliseconds. When a tab moves to the background, Safari applies strict limitations:
- Frequency Reduction: Safari throttles the execution rate of timers in background tabs so they fire no more than once per second (1000 milliseconds).
- Timer Alignment (Coalescing): If a background tab has multiple timers set to go off at slightly different times (e.g., at 100ms, 250ms, and 400ms), Safari delays and groups them so they all fire simultaneously at the next 1-second interval.
- Deep Suspension on iOS: On iPhones, Safari is even more aggressive. If a tab remains in the background for a short period and is not playing audio or performing a critical task, iOS will freeze the tab entirely, halting all JavaScript timers until the user taps on that tab again.
Occlusion Detection on macOS
Safari’s power-saving measures do not just apply to unselected tabs; they also apply to "occluded" windows on macOS.
An occluded window is an active browser tab that is completely covered by another application on your MacBook screen—for example, if you have Safari open, but you pull a full-screen Pages document or Terminal window directly over it.
Because Safari is tightly integrated with macOS, the operating system
informs WebKit when a browser window is 100% obscured by other windows.
Safari immediately treats that occluded window identically to a
background tab. It sets the page’s visibility state to
hidden, halts requestAnimationFrame, and
throttles all JavaScript timers to once per second. The moment even a
single pixel of the Safari window is revealed, normal execution speeds
resume instantly.
How This Extends Battery Life
The primary goal of throttling and coalescing is to maximize the time the processor spends in deep sleep states (known as C-states).
Every time a JavaScript timer fires, the CPU must wake up from a
low-power state, execute the task, and go back to sleep. Waking the
processor up consumes a significant spike of energy. By stopping
requestAnimationFrame and forcing scattered JavaScript
timers to fire together only once per second, Safari drastically reduces
the number of CPU interrupts. This allows the Apple Silicon or Intel
processor in a MacBook, and the A-series chip in an iPhone, to remain
powered down for longer consecutive stretches, significantly extending
the device's battery life.