-
Notifications
You must be signed in to change notification settings - Fork 26.3k
After render notifies scheduler (afterRender hooks are guaranteed to run) #54083
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
Conversation
6509ec8
to
1f081c8
Compare
1f081c8
to
db49d48
Compare
fdb2bae
to
09fc627
Compare
09fc627
to
8609b34
Compare
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.
As far as I can tell the logic around scheduling CD upon installation of a render hook needs tests.
// When we remove a view from the DOM, we need to rerun afterRender hooks | ||
// We don't necessarily needs to run change detection. DOM removal only requires | ||
// change detection if animations are enabled (this notification is handled by animations). | ||
lView[ENVIRONMENT].changeDetectionScheduler?.notify(NotificationType.AfterRenderHooks); |
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.
nit: currently the NotificationType
indicates what should happen in the scheduler. An alternative would be send a notification indicating what happened (ex.: view added, after render hook created etc.) and leave it to the scheduler to figure out appropriate actions.
While I would structure code this way I do recognize that it might be a personal preference so feel free to ignore.
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 thought about this as well but decided against it because it’s one additional type of thing that isn’t really used in any way. That is, we’d notify with a bunch of different sources and then map all those sources back to just two actions again. Until we have a use case for interpreting the sources in different ways (even just for logging), I feel this approach is much simpler.
This commit updates the `afterRender` and `afterNextRender` hooks to notify the scheduler (which subsequently schedules change detection) when created. This makes the hooks similar to `requestAnimationFrame`, which requests that the browser schedule a rendering operation. This reqeust is not conditional. Even if there was nothing to repaint, the `requestAnimationFrame` callback will execute. In Angular, this is useful because callers of `afterNextRender` don't necessarily have any way of knowing whether a change detection is even scheduled. For example, the anchor scrolling with the Angular Router needs to wait for rendering to complete before attempting to scroll because rendering can affect the size of the page. However, if the user is already on the page that the navigation is targeting, such as navigating to an anchor on the page, there is nothing new for the Router to render so a render might not even be scheduled. Related to angular#53985, which could use `afterNextRender` instead of `setTimeout` to ensure the scrolling happens in the same frame as the page rendering, but would not necessarily work without this change (as described above). Note that the scrolling _cannot_ use a microtask to ensure scrolling happens in the same frame because `NgZone` will ensure microtasks flush before change detection, so it would cause the scroll to happen before rendering.
…ication source Do not refresh views if the only thing that notified the scheduler was registration of a new render hook.
8609b34
to
935b4ff
Compare
Added a couple tests. Good catch. |
935b4ff
to
0549c24
Compare
@@ -313,9 +339,9 @@ describe('Angular with NoopNgZone', () => { | |||
await whenStable(); | |||
expect(host.innerHTML).toEqual(''); | |||
host.appendChild(component.instance.elementRef.nativeElement); | |||
// reattaching non-dirty view does not notify scheduler | |||
// reattaching non-dirty view does not notifies scheduler because afterRender hooks must run |
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.
"does not notifies" => "notifies"
0549c24
to
1a12a02
Compare
This commit ensures that render hooks are rerun when a node is attached or detached. We do not necessarily need to run change detection but DOM did change so render hooks should execute.
1a12a02
to
64c846b
Compare
This PR was merged into the repository by commit 2787c50. |
) This commit updates the `afterRender` and `afterNextRender` hooks to notify the scheduler (which subsequently schedules change detection) when created. This makes the hooks similar to `requestAnimationFrame`, which requests that the browser schedule a rendering operation. This reqeust is not conditional. Even if there was nothing to repaint, the `requestAnimationFrame` callback will execute. In Angular, this is useful because callers of `afterNextRender` don't necessarily have any way of knowing whether a change detection is even scheduled. For example, the anchor scrolling with the Angular Router needs to wait for rendering to complete before attempting to scroll because rendering can affect the size of the page. However, if the user is already on the page that the navigation is targeting, such as navigating to an anchor on the page, there is nothing new for the Router to render so a render might not even be scheduled. Related to #53985, which could use `afterNextRender` instead of `setTimeout` to ensure the scrolling happens in the same frame as the page rendering, but would not necessarily work without this change (as described above). Note that the scrolling _cannot_ use a microtask to ensure scrolling happens in the same frame because `NgZone` will ensure microtasks flush before change detection, so it would cause the scroll to happen before rendering. PR Close #54083
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Commit 1
refactor(core): registering afterRender hooks notify scheduler
This commit updates the
afterRender
andafterNextRender
hooks tonotify the scheduler (which subsequently schedules change detection)
when created. This makes the hooks similar to
requestAnimationFrame
,which requests that the browser schedule a rendering operation. This
reqeust is not conditional. Even if there was nothing to repaint, the
requestAnimationFrame
callback will execute.In Angular, this is useful because callers of
afterNextRender
don'tnecessarily have any way of knowing whether a change detection is even
scheduled. For example, the anchor scrolling with the Angular Router
needs to wait for rendering to complete before attempting to scroll
because rendering can affect the size of the page. However, if the user
is already on the page that the navigation is targeting, such as
navigating to an anchor on the page, there is nothing new for the Router
to render so a render might not even be scheduled.
Related to #53985, which
could use
afterNextRender
instead ofsetTimeout
to ensure thescrolling happens in the same frame as the page rendering, but would not
necessarily work without this change (as described above). Note that the
scrolling cannot use a microtask to ensure scrolling happens in the
same frame because
NgZone
will ensure microtasks flush beforechange detection, so it would cause the scroll to happen before rendering.
Commit 2
refactor(core): Skip refresh views if render hooks are the only notif…
…ication source
Do not refresh views if the only thing that notified the scheduler was
registration of a new render hook.
Commit 3
refactor(core): render hooks should always run on node attach or detach
This commit ensures that render hooks are rerun when a node is attached
or detached. We do not necessarily need to run change detection but DOM
did change so render hooks should execute.