-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
First pass at IntersectionObserver in Resources #26236
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The possibility of stale size boxes worries me.
src/layout-rect.js
Outdated
* @param {!LayoutRectDef} r1 | ||
* @param {!LayoutRectDef} r2 | ||
* @param {{top: number, bottom: number, left: number, right: number}} r1 | ||
* @param {{top: number, bottom: number, left: number, right: number}} r2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yah, I agree that there's a risk of obfuscation. layoutRectFromDomRect
was made for this.
|
||
// Force all intersecting, non-zero-sized, non-owned elements to be built. | ||
// E.g. ensures that all in-viewport elements are built in prerender mode. | ||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this from?
amphtml/src/service/resources-impl.js
Lines 1134 to 1147 in 4847c7f
if ( | |
!r.isBuilt() && | |
!r.hasOwner() && | |
r.hasBeenMeasured() && | |
r.isDisplayed() && | |
r.overlaps(loadRect) | |
) { | |
this.buildOrScheduleBuildForResource_( | |
r, | |
/* checkForDupes */ true, | |
/* scheduleWhenBuilt */ undefined, | |
/* force */ true | |
); | |
} |
!r.isBuilt() && | ||
!r.isBuilding() && | ||
isIntersecting && | ||
r.isDisplayed(clientRect) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary with isIntersecting
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, it's kinda confusing. isDisplayed
refers to size of the element. You can have an intersecting element with zero size.
|
||
const toUnload = []; | ||
|
||
const promises = entries.map(entry => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that there may be later entries with more up-to-date info on the same element. We may need to work from right to left, and skip the leftmost entires that are old.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this actually happen in practice? I'd be surprised.
const {boundingClientRect, isIntersecting, target, rootBounds} = entry; | ||
// Closure Compiler doesn't recognize boundingClientRect as a ClientRect. | ||
const clientRect = /** @type {!ClientRect} */ (boundingClientRect); | ||
devAssert(target.isUpgraded()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a safe assertion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, we only start observing on upgrade.
const wasIntersecting = r.isInViewport(); | ||
let isDisplayed = this.measureResource_(r, clientRect); | ||
|
||
if (wasIntersecting && !isIntersecting) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we first refactor this so that the Resource
is responsible? Eg, we just call setInViewport(isIntersecting)
and the Resource
can go "oh, shit, I need to build".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like where your head's at, but I definitely disagree with "refactor first". :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM on my side. But please take a look at the experiment override question.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To give file-size approval. I'll do a full review soon.
Partial for #25428.
Guarded by "intersect-resources" experiment flag. IntersectionObserver spec behavior change slated to ship in Chrome 81 in March.
Still a fair amount of TODOs to resolve e.g. dynamic loading rectangle during prerender mode, skipping intersections when scroll velocity is very high.
However, I'd like to start scaling the testing beyond myself (see below). Cost is a minor bundle size increase:
Summary
intersects_()
replaces most ofdiscoverWork_()
, with some exceptions (e.g.idleRenderOutsideViewport
is unimplemented).IntersectionObserverEntry.boundingClientRect
instead ofElement.getBoundingClientRect()
where possible.remeasurePass()
andsetRelayoutTop()
.Testing
Did some manual testing across several components and behaviors. Simple performance tests look roughly comparable.
Next, will write a test plan for @diantekyrie for broader extension coverage.