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

the update intersection observations steps should happen after requestAnimationFrame callbacks and layout #263

Open
dbaron opened this issue Oct 23, 2017 · 18 comments
Assignees

Comments

@dbaron
Copy link
Member

dbaron commented Oct 23, 2017

The section on patching the event loop spec says that the insertion of the new step for processing IntersectionObserver should happen before the step for requestAnimationFrame callbacks.

This differs from the change which has already been edited into the HTML spec, which says it should happen after the requestAnimationFrame callbacks, but before the update of the style and layout.

Both of these feel wrong to me. I think it should run after both the requestAnimationFrame callbacks and after the natural update of the layout, since rAF is primarily a writing callback (so should be early, before the natural style/layout), whereas IntersectionObserver is primarily a reading callback (so should be late, after the natural style/layout). This ordering makes the primary use of the callback less likely to cause extra flush/update cycles.

Changing this probably requires a bit of investigation of both current behavior, and perhaps of whether what's described in the HTML spec actually reflects reality (which last time I was involved in a detailed discussion of it, it seemed not to be the case).

I got here from w3ctag/design-reviews#197.

@dbaron
Copy link
Member Author

dbaron commented Oct 31, 2017

@slightlyoff points out that the records delivered are out-of-date by a refresh cycle or more, which actually changes some of the arguments here, but I need to dig into that further.

@travisleithead
Copy link
Member

This might be interesting for @toddreifsteck to follow as well.

@szager-chromium
Copy link
Collaborator

I think the HTML spec is correct: IO should run after rAF, but before "update the rendering."

Please correct me if I'm wrong, but "update the rendering" doesn't mean "update style and layout." As I understand it, the spec has no concept of "update style and layout". From the point of view of the spec, when DOM is modified the new style and layout is immediately available to javascript.

My understanding is that "update the rendering" means "push pixels to the screen." If that's the case, then I think it's correct to run the IO algorithm before "update the rendering".

@szager-chromium
Copy link
Collaborator

szager-chromium commented Nov 8, 2017 via email

@dbaron
Copy link
Member Author

dbaron commented Nov 22, 2017

Please correct me if I'm wrong, but "update the rendering" doesn't mean "update style and layout." As I understand it, the spec has no concept of "update style and layout". From the point of view of the spec, when DOM is modified the new style and layout is immediately available to javascript.

My understanding is that "update the rendering" means "push pixels to the screen." If that's the case, then I think it's correct to run the IO algorithm before "update the rendering".

I agree the spec should be a lot clearer here, but I believe the intent is the opposite, and that "update the rendering or user interface ... to reflect the current state" does include updating style and layout. At least, that's how I've always read it.

I think any serious attempt to specify the rendering loop couldn't possibly make the assumption that all DOM modifications lead to instantaneous updates to style and layout. I thought the specification defined the concept of flushing these somewhere, but I can't currently find it.

@dbaron
Copy link
Member Author

dbaron commented Nov 22, 2017

Also, I think my statement that the IntersectionObserver steps involve reading and not writing is even stronger given that the script callbacks aren't actually run during those steps. If only the steps in the spec run, then I think it's clear that only reading happens during those steps, and therefore they should occur after style and layout updating happens.

@dbaron
Copy link
Member Author

dbaron commented Feb 1, 2018

OK, I guess I see now that the spec's placement of the updates in the list would make sense given the interpretation of the HTML spec by @szager-chromium in #263 (comment) , whereas with my interpretation of the HTML spec in #263 (comment) I think my proposed movement of the IntersectionObserver updates after the update the rendering steps. So I think resolving this depends on whatwg/html#3246, which in turn probably depends on other things...

@dbaron
Copy link
Member Author

dbaron commented Dec 19, 2018

This was modified a bit by #331 (which I propose changing a little further in #336). And a number of remaining issues are covered by whatwg/html#3246.

But I think one pretty basic issue remains here, which is that I was suggesting that the update intersection observations steps should occur not only after requestAnimationFrame (which #331 does) but also after the natural update of layout (which it doesn't change).

@szager-chromium
Copy link
Collaborator

Let's see if we can wrap this up so it's not looming over the design review.

The current Event Loop spec has the following:

  1. Update the Rendering
    ...
    11. For each fully active Document in docs, run the animation frame callbacks for that Document, passing in now as the timestamp.
    12. For each fully active Document in docs, run the update intersection observations steps for that
    Document, passing in now as the timestamp.
    13. Invoke the mark paint timing algorithm for each Document object in docs.
    14. For each fully active Document in docs, update the rendering or user interface of that Document and its browsing context to reflect the current state.
  2. (maybe start an idle period)
    ...

I don't really see how it makes sense to move IntersectionObserver any later in that list, @dbaron, WDYT?

@szager-chromium
Copy link
Collaborator

I think step 14 in "Update the rendering" is the really mysterious one. It updates both the "rendering or user interface" and the "browsing context".

"Update the rendering or user interface" sounds like pushing pixels to me, which -- at least in chromium -- definitely happens after IntersectionObserver runs (and I think that ordering makes sense).

I'm not sure what "Update the browsing context" means here, so I don't know if it should happen before or after IntersectionObserver.

@dbaron
Copy link
Member Author

dbaron commented Nov 5, 2019

So the point I've been making (see, e.g., #263 (comment)) is that I think the "update intersection observations steps" should happen after the UA does layout. (The places where script is run might also do things that flush layout, but there's a default point where layout happens, and I think that should be before the update intersection observations steps.)

@rniwa
Copy link

rniwa commented Nov 5, 2019

FWIW, HTML5 spec's current model is that style & layout are always up-to-date so update the rendering means to update the rendering on the screen as suggested in #263 (comment)

@dbaron
Copy link
Member Author

dbaron commented Nov 6, 2019

I don't think it's clear that that's the current spec model; I think it's at best unspecified. (And certainly none of the spec's editors said in whatwg/html#3246 that that's the current spec model.)

@rniwa
Copy link

rniwa commented Nov 6, 2019

I don't think it's clear that that's the current spec model; I think it's at best unspecified.

I think it's pretty clear from the existing API that it needs to be that way. If someone modifies CSS rules then invokes offsetTop, left, etc... in the middle of resize event or scroll event handler, those events would see the updated dimensions, not some stale state from the past. In fact, this is pretty much how all browsers behave.

@dbaron
Copy link
Member Author

dbaron commented Nov 6, 2019

I'm not disagreeing with the idea that APIs return up-to-date state.

@dbaron
Copy link
Member Author

dbaron commented Nov 6, 2019

What I'm saying is that I've always seen that "update the rendering" statement in the spec as the start of a so-far-very-incomplete attempt to specify the flushing and batching that browsers do, and I've always interpreted it to say that that's where the default (i.e., before painting) style and layout flushes happen.

@falsandtru
Copy link

I met this problem. IntersectionObserver always reports all observation targets. This behavior on the spec makes IntersectionObserver completely useless.

@falsandtru
Copy link

I'm combining IntersectionObserver and requestAnimationFrame as follows:

  async function display() {
    let start = Date.now();
    let delta = 0;
    let time = 0;
    let resource = 100;
    for (const el of update(document.getElementById('editor').value)) {
      el.parentNode
         ? observer.observe(el)
         : observer.unobserve(el);
      delta = Date.now() - start;
      time += delta;
      resource = resource - delta > 0
        ? resource - delta
        : void await new Promise(requestAnimationFrame) || 300;
      start = Date.now();
    }
    return time += Date.now() - start;
  }

aarongable pushed a commit to chromium/chromium that referenced this issue Jul 2, 2024
This CL complements the case in which the PEPC styling is changed,
causing a move that but then move back instantaneously in
requestAnimationFrame callback.
Based on w3c/IntersectionObserver#263, it
seems like if the re-layout happen in the requestAnimationFrame
callback, IntersectionObserver won't send us a notification about a
visibility change event, even if the layout totally hides the PEPC.

We had another measure, calculating the intersection rect with the
viewport using lifecycle update events, but that didn't work either
because the intersection rect with the viewport stayed the same.
So, we're making sure that even styling changes that affect the
intersection rect will trigger the cooldown time, no matter if they
happen in requestAnimationFrame or not.

Fixed: 347509736, 348359040
Change-Id: I98dde8d42d696912d499b83be309630a1f4c9392
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5658195
Reviewed-by: Yi Gu <[email protected]>
Commit-Queue: Thomas Nguyen <[email protected]>
Reviewed-by: Mason Freed <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1322092}
aarongable pushed a commit to chromium/chromium that referenced this issue Jul 12, 2024
This CL complements the case in which the PEPC styling is changed,
causing a move that but then move back instantaneously in
requestAnimationFrame callback.
Based on w3c/IntersectionObserver#263, it
seems like if the re-layout happen in the requestAnimationFrame
callback, IntersectionObserver won't send us a notification about a
visibility change event, even if the layout totally hides the PEPC.

We had another measure, calculating the intersection rect with the
viewport using lifecycle update events, but that didn't work either
because the intersection rect with the viewport stayed the same.
So, we're making sure that even styling changes that affect the
intersection rect will trigger the cooldown time, no matter if they
happen in requestAnimationFrame or not.

(cherry picked from commit b45d131)

Fixed: 347509736, 348359040
Change-Id: I98dde8d42d696912d499b83be309630a1f4c9392
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5658195
Reviewed-by: Yi Gu <[email protected]>
Commit-Queue: Thomas Nguyen <[email protected]>
Reviewed-by: Mason Freed <[email protected]>
Cr-Original-Commit-Position: refs/heads/main@{#1322092}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5674519
Bot-Commit: Rubber Stamper <[email protected]>
Reviewed-by: Kouhei Ueno <[email protected]>
Cr-Commit-Position: refs/branch-heads/6533@{#1345}
Cr-Branched-From: 7e0b87e-refs/heads/main@{#1313161}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants