Proposal: Display Locking


#1

Github repo is here. Explainer is below:

Display Locking

This is a short proposal for Display Locking. For more details, see the detailed explainer.

Problem

Websites frequently rely on dynamic content to present information. This means that DOM is often manipulated using script to present rich and dynamic content. There are cases when this can cause slow rendering phase updates, including script to update views, style updates, layout, and paint. This, in turn, causes jank or noticeable delay when presenting content, because rendering phase is updated synchronously with user interactions and requestAnimationFrame script.

The following are a few of the common patterns that can cause jank:

  • Resizing multi-pane UI with complex layout within each pane (e.g. IDEs)
  • Adding widgets with complex DOM.
  • Dynamically displaying content based on the current value of text input.
  • Measuring layout of otherwise hidden DOM with intent of sizing containers.

Developers are aware of these issues and build systems to avoid adding complex DOM at once in order to prevent jank. As an example, ReactJS is adding the ability to do async operations to help with this problem.

Proposal

This document proposes to augment user-agent APIs to help address the problem of slow rendering phase updates. Specifically, we propose a concept of display locking an element.

If an element is locked for display, it means that any DOM updates to its subtree are not rendered immediately. Instead, when the lock is committed, the user-agent processed rendering updates co-operatively, yielding periodically to allow script or user interactions to happen.

The visual content of an element which is locked for display does not change. One option is that the visual output is fixed to whatever content was present at the time the lock was acquired, and remains this way until the lock is released and all associated promises are resolved. Another possiblity is effectively making the locked subtree visibility: hidden, meaning that we don’t display any content while work is completed.

There are other possible options here, such as displaying developer specified content. The details of this are up for discussion, but the consistent result is that the visual representation of the modified DOM is not necessarily rendered to screen, affording the user-agent the opportunity to break the work up into smaller pieces.

Example

async function updateDom() {
  let element = document.getElementById("container");

  // Get and acquire a lock, causing the element to be locked.
  let lock = element.getDisplayLock();
  await lock.acquire();

  // Modify element's subtree. The DOM is modified immediately, same as without
  // display locking. However, rendering of the element is delayed.
  element.innerHTML = ...;

  // Commit the lock. This returns a promise. The user-agent starts to
  // co-operatively process steps required to render the modified subtree,
  // including style, layout, and painting. When the user-agent is done
  // with these steps, the promise is resolved.
  lock.commit();
}

In cases where DOM manipulations would cause jank, this instead allows the user-agent to split up the work across several frames, yielding for script and user interactions. When the updates are finished processing, the result is displayed without jank.

Further reading

EDIT: Expanded on the visual content of locked element description.


#2

Hi! I haven’t read the detailed explainer yet, but I like to say that I like the idea!


#3

Just some initial reactions:

  • the naming seems very close to orientation lock, which deals with locking the display (to orientations) - that might cause confusion. Similarly with the wake lock API.
  • how does this play with css will-change (if at all)?

Rick Byers and some other folks had proposed a generic mechanism for “web locks”, parts of which look similar to this. Might help to align with that?