Angular的变更检测和ngZone

数据的双向绑定: 其实数据的流向始终是单项的, 而将数据和DOM元素关联起来就是双向绑定, 即通过属性的绑定数据从组件流到DOM元素, 通过事件的绑定数据从DOM元素流回组件. angular框架自己实现一套比较完善的双向绑定.

进行数据检测

angular其实是在检测到异步事件的时候去进行数据检测的, angular所关注的异步事件可以分为3大类:

  • 视图中绑定的事件, 如: click
  • 接口的回调事件
  • 延时事件, 如: setTimeout, setInterval

那么angular是如何得到这些异步事件的呢? 就是通过我们接下来要聊的Zone.js了

Zone.js

Zone.js是Angular团队为我们带来的一个新库

破狼有一篇文章详细的介绍了zone.js http://www.cnblogs.com/whitewolf/p/zone-js.html

现在我们先了解一些基础的信息:

  • zone.js采用猴子补丁(Monkey-patched)的暴力方式将JavaScript中的异步任务都包裹了一层,使得这些异步任务都将运行在zone的上下文中。每一个异步的任务在zone.js都被当做为一个Task,并在Task的基础上zone.js为开发者提供了执行前后的钩子函数(hook)。

    • onZoneCreated:产生一个新的zone对象时的钩子函数。zone.fork也会产生一个继承至基类zone的新zone,形成一个独立的zone上下文;
    • beforeTask:zone Task执行前的钩子函数;
    • afterTask:zone Task执行完成后的钩子函数;
    • onError:zone运行Task时候的异常钩子函数;
  • 在zone.js中fork方法会产生一个继承至zone的子类,并在fork函数中可以配置特定的钩子方法,形成独立的zone上下文。而run方法则是启动执行业务代码的对外接口。

    1
    2
    3
    4
    5
    6
    7
    zone.fork({
    onZoneCreated: log("onZoneCreated"),
    beforeTask: log("beforeTask"),
    afterTask: log("afterTask"),
    }).run(function(){
    ...
    })

angular中的zone

在Angular2源码中,有一个ApplicationRef类,其作用是用来监听ngZone中的onTurnDone事件,不论何时只要触发这个事件,那么将会执行一个tick()方法用来告诉Angular去执行变化监测。

1
2
3
4
5
6
7
8
9
10
11
12
13
class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];

constructor(private zone: NgZone) {
this.zone.onTurnDone
.subscribe(() => this.zone.run(() => this.tick());
}

tick() {
this.changeDetectorRefs
.forEach((ref) => ref.detectChanges());
}
}