Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Closed
wants to merge 3 commits into from

Conversation

atscott
Copy link
Contributor

@atscott atscott commented Jan 26, 2024

Commit 1

refactor(core): registering afterRender hooks notify scheduler

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.

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.

@atscott atscott added state: blocked area: core Issues related to the framework runtime labels Jan 26, 2024
@ngbot ngbot bot added this to the Backlog milestone Jan 26, 2024
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 6509ec8 to 1f081c8 Compare February 3, 2024 00:44
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 1f081c8 to db49d48 Compare February 28, 2024 21:56
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch 2 times, most recently from fdb2bae to 09fc627 Compare February 28, 2024 22:36
@atscott atscott marked this pull request as ready for review February 28, 2024 22:38
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 09fc627 to 8609b34 Compare March 4, 2024 20:24
Copy link
Member

@pkozlowski-opensource pkozlowski-opensource left a 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);

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.

Copy link
Contributor Author

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.

atscott added 2 commits March 6, 2024 11:09
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.
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 8609b34 to 935b4ff Compare March 6, 2024 20:29
@atscott
Copy link
Contributor Author

atscott commented Mar 6, 2024

As far as I can tell the logic around scheduling CD upon installation of a render hook needs tests.

Added a couple tests. Good catch.

@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 935b4ff to 0549c24 Compare March 7, 2024 00:18
@@ -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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"does not notifies" => "notifies"

@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 0549c24 to 1a12a02 Compare March 7, 2024 16:44
@atscott atscott added the action: merge The PR is ready for merge by the caretaker label Mar 7, 2024
@atscott atscott removed the request for review from alxhub March 7, 2024 18:55
@atscott atscott added the target: rc This PR is targeted for the next release-candidate label Mar 7, 2024
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.
@atscott atscott force-pushed the afterRenderNotifiesScheduler branch from 1a12a02 to 64c846b Compare March 7, 2024 18:58
@atscott
Copy link
Contributor Author

atscott commented Mar 7, 2024

This PR was merged into the repository by commit 2787c50.

atscott added a commit that referenced this pull request Mar 7, 2024
)

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
atscott added a commit that referenced this pull request Mar 7, 2024
…ication source (#54083)

Do not refresh views if the only thing that notified the scheduler was
registration of a new render hook.

PR Close #54083
atscott added a commit that referenced this pull request Mar 7, 2024
…ch (#54083)

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.

PR Close #54083
@atscott atscott closed this in 53e7439 Mar 7, 2024
atscott added a commit that referenced this pull request Mar 7, 2024
…ication source (#54083)

Do not refresh views if the only thing that notified the scheduler was
registration of a new render hook.

PR Close #54083
atscott added a commit that referenced this pull request Mar 7, 2024
…ch (#54083)

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.

PR Close #54083
mmalerba added a commit to mmalerba/components that referenced this pull request Mar 7, 2024
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Apr 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: core Issues related to the framework runtime target: rc This PR is targeted for the next release-candidate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants