Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust event loop processing model to allow asynchronous layout of frames #3727

Open
chrishtr opened this issue May 30, 2018 · 3 comments
Open
Labels
interop Implementations are not interoperable with each other topic: agent The interaction with JavaScript's agent and agent cluster concepts topic: event loop

Comments

@chrishtr
Copy link
Contributor

chrishtr commented May 30, 2018

Currently, the event loop processing model [1] does not make reference to the concept of
computing style or layout. It is assumed that updates to the DOM are atomic, and it
is an implementation detail whether browsers update style or layout at a later time. This
is true even for cases with multiple documents (frames), meaning that style and layout
are updated atomically for all frames, at least as far as script can observe.

In practice, all browsers update style and layout during rendering frame generation, which
is basically the same as step 3 from [1], "update the rendering". They do this because it
is more efficient to update style and layout lazily than eagerly, in the presence of script
which may make a sequence of style- and layout-inducing DOM mutations in one synchronous
block.

Further, Chromium in particular also updates all frames' style and layout at the same time
(except when cross-domain iframes are "throttled", which concept is referenced in step 7.4 of [1]).
However, even in this situation, Chromium will perform a synchronous style or layout if script references
style- or layout-inducing CSS properties on DOM objects, so from the script point of view,
style and layout for such frames are still atomic w.r.t. the main frame. (*)

The assumption of atomicity starts to break down with the desire to implement cross-domain
iframes in separate processes (Chrome calls this feature Site Isolation [4]), which is
necessary for security and desired for performance.

To avoid unreasonable implementation difficulty and poor performance in this multi-process scenario,
it is necessary to decouple style/layout update of each frame from other frames. This means that in
cases where one frame's size depends on the style or layout of another frame, we do not
necessarily force them to update in lockstep. Consider this example:

a.com frame:


var f = document.querySelector(‘iframe’);
f.width = 123;
f.clientWindow.postMessage(“foo”, ”b.com”);

b.com sub-frame:

onmessage = () => {
  console.log(
      document.body.clientWidth);
};

In this code, b may observe a width that is not 123, until such time as a.com decides to render and then send a message to b.com's rendering process to update its layout.

An edit to the event processing model could be made, perhaps as follows:

  • Expand 7.12 to specify the concept of style-and-layout, expanding on what ResizeObserver suggests [2]
  • Specify that Documents which are not same-origin do not necessarily run on the same browsing context event loop task. Still require that the task which runs for a parent Document occurs earlier than that for a child Document.

The specification for behavior of methods like clientWidth or offsetWidth is part of the CSSOM spec,
but also needs to be edited to make clear that in the presence of multiple Documents, they are not
necessarily updated atomically.

[1] https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model
[2] https://wicg.github.io/ResizeObserver/#html-event-loop
[3] https://drafts.csswg.org/cssom-view/
[4] http://www.chromium.org/Home/chromium-security/site-isolation

(*) With the above spec change, Chrome's behavior could be changed to avoid synchronous style-and-layout in this case also.

@chrishtr
Copy link
Contributor Author

chrishtr commented May 30, 2018

Also, the spec should be edited so that the order of postMessage to a child frame relative to
rendering event loop tasks is specified, if the postMessage occurs during a callback executed in step 7 of the event loop processing model.

Consider this code:

a.com frame:

requestAnimationFrame(function() {
  var f = document.querySelector(‘iframe’);
  f.width = 123;
  f.clientWindow.postMessage(“foo”, ”b.com”);
}

b.com sub-frame:

onmessage = () => {
console.log(
document.body.clientWidth);
};

In this scenario, it should be guaranteed that clientWidth is always 123 for b.com's frame. This is because postMessage puts the message as a task on the event loop, and the current task, at the time of the requestAnimationFrame, is a rendering task that runs step 7, and hence updates the layout of the iframe. This update should immediately send a resize message, if necessary, to the sub-frame, preceding any other tasks on the event loop (perhaps that resize message should be spec'd as a microtask).

This is important because it allows developers to cope with frame rendering asynchrony in a reasonable way, by waiting for rendering of a parent frame before dispatching messages to the child.

@annevk
Copy link
Member

annevk commented May 31, 2018

See also #3497 and #3506. We should probably start tracking all issues that fall out of out-of-process similar-origin window agents in some way.

We need a big revamp of the standard that clearly allocates similar-origin window agents (to which the event loop will have to belong), allocates windows within those, and documents within those, and makes them play well with browsing contexts and such. And then we need to change the WindowProxy and Location object setup such that they're no longer 1:1 with windows, but end up acting as proper proxies with message passing. Once we have that it'd be much easier to define a reasonable scheduling of all these things.

Unfortunately this kind of revamping is extremely tough and I haven't really been able to make a dent thus far.

cc @bzbarsky

@annevk annevk added the interop Implementations are not interoperable with each other label May 31, 2018
@annevk annevk added the topic: agent The interaction with JavaScript's agent and agent cluster concepts label Feb 26, 2019
@bzbarsky
Copy link
Contributor

@mystor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interop Implementations are not interoperable with each other topic: agent The interaction with JavaScript's agent and agent cluster concepts topic: event loop
Development

No branches or pull requests

3 participants