我发现了一个案例,其中更改检测因错误而进入无限循环。
有问题的代码:
@Component({selector: "signup-comp"})
@View({
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
template: `
<form #f="form" (ng-submit)='onSignUp(f.value)'>
<div ng-control-group='credentials' #credentials="form">
Login <input type='text' ng-control='login'>
Password <input type='password' ng-control='password'>
</div>
<div *ng-if="!d.valid">Credentials are invalid</div>
<div ng-control-group='personal'>
Name <input type='text' ng-control='name'>
</div>
<button type='submit'>Sign Up!</button>
</form>
`
})
关键是ng-if
表达式!d.valid
。 d
未定义,这会触发无限循环。
这是一个完整的 Plunker 示例。
似乎<div ng-control-group='credentials'></div>
与ng-if
足以触发该错误。
我找到了根本原因:
NgControlGroup
声明了一个onInit
方法,它通过PromiseWrapper.resolve
安排一些异步完成的工作。
问题是onInit
实际上可以被多次调用 - 如果更改检测运行并且从未成功完成,则会调用它。 如果有异常变化后,检测过程中发生的onInit
被调用时, AbstractChangeDetector.alreadyChecked
将不会设置和onInit
将再次下一个滴答期间运行。 由于onInit
中的NgControlGroup
调度异步工作,下一个滴答将立即发生,从而导致崩溃循环。
最有用的评论
我找到了根本原因:
NgControlGroup
声明了一个onInit
方法,它通过PromiseWrapper.resolve
安排一些异步完成的工作。问题是
onInit
实际上可以被多次调用 - 如果更改检测运行并且从未成功完成,则会调用它。 如果有异常变化后,检测过程中发生的onInit
被调用时,AbstractChangeDetector.alreadyChecked
将不会设置和onInit
将再次下一个滴答期间运行。 由于onInit
中的NgControlGroup
调度异步工作,下一个滴答将立即发生,从而导致崩溃循环。