Skip to content

Lifecycle recursion - #28239

Closed
marclaval wants to merge 2 commits into
angular:masterfrom
marclaval:lifecycleRecursion
Closed

marclaval wants to merge 2 commits into
angular:masterfrom
marclaval:lifecycleRecursion

Conversation

@marclaval

@marclaval marclaval commented Jan 18, 2019 •

Copy link
Copy Markdown
Contributor

This PR fixes FW-832.

@marclaval
marclaval requested review from a team January 18, 2019 16:36
@googlebot

Copy link
Copy Markdown

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@marclaval

marclaval commented Jan 18, 2019 •

Copy link
Copy Markdown
Contributor Author

More details about the fix. The integration test that is enabled here shows a very interesting property of the ViewEngine: the init hooks (OnInit, AfterContentInit, and AfterViewInit) are always executed once and only once, even if they recurse or throw.

In fact, this logic is documented here:

// This function calls the ngAfterContentCheck, ngAfterContentInit,
// ngAfterViewCheck, and ngAfterViewInit lifecycle hooks (depending on the node
// flags in lifecycle). Unlike ngDoCheck, ngOnChanges and ngOnInit, which are
// called during a pre-order traversal of the view tree (that is calling the
// parent hooks before the child hooks) these events are sent in using a
// post-order traversal of the tree (children before parents). This changes the
// meaning of initIndex in the view state. For ngOnInit, initIndex tracks the
// expected nodeIndex which a ngOnInit should be called. When sending
// ngAfterContentInit and ngAfterViewInit it is the expected count of
// ngAfterContentInit or ngAfterViewInit methods that have been called. This
// ensure that despite being called recursively or after picking up after an
// exception, the ngAfterContentInit or ngAfterViewInit will be called on the
// correct nodes. Consider for example, the following (where E is an element
// and D is a directive)
// Tree: pre-order index post-order index
// E1 0 6
// E2 1 1
// D3 2 0
// E4 3 5
// E5 4 4
// E6 5 2
// E7 6 3
// As can be seen, the post-order index has an unclear relationship to the
// pre-order index (postOrderIndex === preOrderIndex - parentCount +
// childCount). Since number of calls to ngAfterContentInit and ngAfterViewInit
// are stable (will be the same for the same view regardless of exceptions or
// recursion) we just need to count them which will roughly correspond to the
// post-order index (it skips elements and directives that do not have
// lifecycle hooks).
//
// For example, if an exception is raised in the E6.onAfterViewInit() the
// initIndex is left at 3 (by shouldCallLifecycleInitHook() which set it to
// initIndex + 1). When checkAndUpdateView() is called again D3, E2 and E6 will
// not have their ngAfterViewInit() called but, starting with E7, the rest of
// the view will begin getting ngAfterViewInit() called until a check and
// pass is complete.
//
// This algorthim also handles recursion. Consider if E4's ngAfterViewInit()
// indirectly calls E1's ChangeDetectorRef.detectChanges(). The expected
// initIndex is set to 6, the recusive checkAndUpdateView() starts walk again.
// D3, E2, E6, E7, E5 and E4 are skipped, ngAfterViewInit() is called on E1.
// When the recursion returns the initIndex will be 7 so E1 is skipped as it
// has already been called in the recursively called checkAnUpdateView().

In Ivy, we don't manage these cases at all.

  • The recursion one can be easily solved by adding a few flags to guard against it.
  • The throw one is more challenging. Within a view, the execution on all the init hooks is actually a sequence. If one of them throws, then the exception is not caught by the framework and the current change detection is stopped. During the next change detection, the sequence will resume where it stopped (and all the check hooks will be executed as usual). This means that:
    • the state of this sequence is kept in the view
    • init hooks may be executed in any view pass, not only the first one
    • collected ngOnInit, ngAfterContentInit, ngAfterViewInit are special hooks that needs to be flagged as such, as oppposed to ngDoCheck, ngAfterViewChecked, etc. Executing a special hook changes the state, while executing the other ones don't.

@marclaval marclaval added action: review The PR is still awaiting reviews from at least one requested reviewer target: major This PR is targeted for the next major release comp: ivy labels Jan 18, 2019
@ngbot ngbot Bot added this to the needsTriage milestone Jan 18, 2019
@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

@googlebot

Copy link
Copy Markdown

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@mhevery mhevery left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Made some changes cda7b03993

@mhevery mhevery added cla: yes and removed cla: no labels Jan 25, 2019
@googlebot

Copy link
Copy Markdown

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

@mhevery mhevery added the action: merge The PR is ready for merge by the caretaker label Jan 25, 2019
@mhevery

mhevery commented Jan 25, 2019

Copy link
Copy Markdown
Contributor

@kara kara added merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jan 25, 2019
@kara

kara commented Jan 25, 2019

Copy link
Copy Markdown
Contributor

@Mlaval Looks like this needs a symbol tests updated

@googlebot

Copy link
Copy Markdown

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@marclaval

Copy link
Copy Markdown
Contributor Author

@kara I've updated the symbols, it should be good to go

@kara kara added cla: yes and removed cla: no labels Jan 25, 2019
@googlebot

Copy link
Copy Markdown

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

@kara kara added merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note and removed merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note labels Jan 25, 2019
@kara
kara force-pushed the lifecycleRecursion branch from 648356f to 1bf6460 Compare January 25, 2019 21:23
@googlebot

Copy link
Copy Markdown

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@kara kara added cla: yes and removed cla: no labels Jan 25, 2019
@googlebot

Copy link
Copy Markdown

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

@kara
kara force-pushed the lifecycleRecursion branch from 1bf6460 to 466073b Compare January 25, 2019 22:30
@googlebot

Copy link
Copy Markdown

CLAs look good, thanks!

@jasonaden jasonaden closed this in 8737506 Jan 25, 2019
vetom pushed a commit to vetom/angular that referenced this pull request Jan 31, 2019
vetom pushed a commit to vetom/angular that referenced this pull request Jan 31, 2019
@angular-automatic-lock-bot

Copy link
Copy Markdown

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 Sep 14, 2019
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 cla: yes merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note target: major This PR is targeted for the next major release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants