To help combat this, Google is working on implementing the Long Task API in Chrome. This allows web apps to identify what in particular is causing poor performance, and give web developers the information they need to fix it. For example, web apps can set up a listener for "long tasks" (processes that are taking longer than 50 milliseconds) which identify where the process came from in the first place. This could narrow down performance issues to a specific element, like an ad unit or buggy embedded video.
This, combined with the aggressive background tab throttling coming in a future release (although that applies to the desktop only, Chrome for Android already has something similar), should help reduce the chances of Chrome slowing down. The Long Task API just received 'Intent to Ship' in Chrome, meaning it will be enabled by default in Chrome soon. If you're interested in the technical details, see the source links below.
As the page is loading and while the user is interacting with the page afterwards, both the application and browser queue various events that are then executed by the browser -- e.g. the user agent schedules input events based on user’s activity, the application schedules callbacks for requestAnimationFrame and other callbacks etc. Once in the queue, these events are then dequeued one-by-one by the browser and executed — see “the anatomy of a frame” for a high-level overview of this process in Blink.
However, some tasks can take a long time (multiple frames), and if and when that happens, the UI thread is locked and all other tasks are blocked as well. To the user this is commonly visible as a “locked up” page where the browser is unable to respond to user input; this is a major source of bad user experience on the web today:
- Delayed “time to Interactive”: while the page is loading long tasks often tie up the main thread and prevent the user from interacting with the page even though the page is visually rendered. Poorly designed third-party content is a frequent culprit.
- High/variable input latency: critical user interaction events (tap, click, scroll, wheel, etc) are queued behind long tasks, which yields janky and unpredictable user experience.
- High/variable event handling latency: similar to input, but for processing event callbacks (e.g. onload events, and so on), which delay application updates.
- Janky animations and scrolling: some animation and scrolling interactions require coordination between compositor and main threads; if the main thread is blocked due to a long task, it can affect responsiveness of animations and scrolling.
Some applications (and RUM vendors) are already attempting to identify and track cases where “long tasks” happen. For example, one known pattern is to install a ~short periodic timer and inspect the elapsed time between the successive calls: if the elapsed time is greater than the timer period, then there is high likelihood that one or more long tasks have delayed execution of the timer. This mostly works, but it has several bad performance implications: the application is polling to detect long tasks, which prevents quiescence and long idle blocks (see requestIdleCallback); it’s bad for battery life; and there is no way to know what caused the delay. (e.g. first party vs third party code)
RAIL performance model suggests that applications should respond in under 100ms to user input; for touch move and scrolling in under 16ms. Our goal with this API is to surface notifications about tasks that may prevent the application from hitting these targets.