什么时候触发
任何的异步操作都可以触发,实现DoCheck接口, 可以知道检测何时发生:
- XHR 请求
- Event,各种异步事件
- setTimeout/setInterval
一次button点击事件+一次GET请求可以触发8次检测
Angular实现机制
NgZone
Zone依赖于zone.js, 这是一个异步拦截器,针对里面封装的异步事件进行监听,有很多hooks可以获取异步事件的上下文. 默认情况下,Zone里面的run函数会涵盖大多数的异步方法,在异步结束的时候自动触发变更检测就好像:
zone.fork({ beforeTask: () => { console.log('hi, beforeTask in.'); }, afterTask: () => { console.log('hi, afterTask in.'); } }).run(function () { zone.inTheZone = true; setTimeout(function () { console.log('in the zone: ' + !!zone.inTheZone); }, 0); });
如何关闭变更检测
NgZong
this.zone.runOutsideAngular(() => {
// async 操作
});
改变变更检测规则
@Component({ selector: 'newsletter', changeDetection: ChangeDetectionStrategy.OnPush, template: `...` })
Angular 父子组建默认加载顺序
父类首先init,
传参给子类,触发子类的onChange方法,
子类init,兄弟类init
传参给孙子类,触发孙子类的onChange方法,
孙子类init,
孙子after view
子after view, 兄弟类after view
father after
如果记不住可以把它的运行顺序当作函数调用顺序,父类调用完调子类子类调用孙子类,孙子类调用完。返回给子类再返回给父类
默认变更检测触发顺序
此时如果改变孙子类的数据,变更检测的触发顺序如下:
可以看出来默认情况下是由上至下传播的,当最底层的组件变更,他会首先找到顶层组件触发变更检测
当brother变更的时候 如下:
然后很神奇的我们就会发现,和上面的一模一样
所以其实当组件树的任何一个节点发生变更检测,他都会由上而下的check变更
更改变更检测策略后
改变子类策略
此时,在子类触发变更:
这时候我们可以看到孙子类的变更没有触发