Angular学习笔记(三)生命周期钩子
钩子
在组件生命的不同阶段(初始化→渲染→存活→销毁),一般会暴露出一些“接口”,开发者可以利用这些接口来实现一些自己的业务逻辑。这种接口在有些框架里面叫做“事件”,在 Angular 里面叫做“钩子”,但其底层的本质都是一样的。
除去构造函数,Angular 一共暴露了8个“钩子”,其描述如下
| 名称 | 描述 |
|---|---|
| ngOnchanges( ) | 当被绑定的输入属性的值发生变化时调用,首次调用发生在 ngOnInit( )之前。 |
| ngOnInit( ) | 在组件开始初始化的时候调用,只调用一次,在第一次调用ngOnChanges( )之后调用 |
| ngDoCheck( ) | 在组件定义的属性或方法变更时调用(脏检查),它的触发相当的频繁且很难预料 |
| ngAfterContentInit( ) | 在组件内容初始化完毕之后调用,只调用一次 |
| ngAfterContentChecked( ) | 在组件每次检查内容发生变更时调用。在ngAfterContentInit( )和每次ngDoCheck( )之后调用 |
| ngAfterViewInit() | 在组件相应的视图初始化之后调用,在第一次ngAfterContentChecked( )之后调用,只调用一次 |
| ngAfterViewChecked() | 在组件每次检查视图发生变更时调用,在每次ngAfterContentInit( )之后调用 |
| ngOnDestory() | 在组件销毁前调用,做一些清理工作,如退订可观察对象和移除事件处理器,防止内存泄漏 |
绿色的4个钩子可能会被执行很多次,紫色的只会执行一次(并没有组件或者指令会实现全部的钩子。)。
应尽量避免在生命周期钩子里面实现复杂的业务逻辑,尤其是那4个会被反复执行的钩子,否则一定会造成界面卡顿。
脏检查的简单原理
机制
默认情况下,在同一个应用中,无论哪个小组件上发生了变化,都会把整个组件树遍历一遍。如果组件树非常庞大,嵌套非常深,很明显会有效率问题。在绝大部分时间里面,并不会出现每个组件都需要刷新的情况,根本没有必要每次都去全部遍历。
所以 Angular 提供了一种叫做OnPush的策略,只要把某个组件上的检测策略设置为OnPush,就可以忽略整个子树,只有当组件的@Input属性发生变化的时候才调用本组件的 ngDoCheck() 钩子。
有一些开发者建议 Angular 项目组把 OnPush 作为默认策略,但是目前还没有得到官方支持,或许在未来的某个版本里面会进行修改。
一点点原理
双向数据绑定的目标很明确:数据模型发生变化之后,界面可以自动刷新;用户修改了界面上的内容之后,数据模型也会发生自动修改。
新版本的 Angular 使用Zone.js这个库,它会把所有可能导致数据模型发生变更的情况全部拦截掉,从而在数据发生变化的时候去通知 Angular 进行刷新。
那么Zone.js 又是怎么实现的呢?
在浏览器环境下,有可能导致数据模型发生变化的情况只有3种典型的回调:
- 事件回调:鼠标、键盘、触摸
- 定时器回调:setTimeout 和 setInterval
- Ajax 回调
Zone.js 覆盖了以上所有的原生实现,当开发者在调用这些函数的时候,并不是调用的原生方法,而是调用的 Zone.js 自己的实现,所以 Zone.js 就可以做一些自己的处理了。

