
大前端成长进阶课程:进入学习
什么是 change detection ?
在应用的开发过程中,state 代表需要显示在应用上的数据。当 state 发生变化时,往往需要一种机制来检测变化的 state 并随之更新对应的界面。这个机制就叫做 change detection 机制。【相关教程推荐:《angular教程》】
在 web 开发中,更新应用界面其实就是对 dom 树进行修改。由于 dom 操作是昂贵的,所以一个效率低下的 change detection 会让应用的性能变得很差。因此,框架在实现 change detection 机制上的高效与否,很大程度上决定了其性能的好坏。
change detection 是如何实现的
angular 可以检测组件数据何时更改,然后自动重新渲染视图以反映该更改。但是在像点击按钮这样的低级事件之后,它怎么能做到这一点呢?
通过 zone , angular 能够实现自动的触发 change detection 机制。
zone 是什么呢?简而言之,zone 是一个执行上下文(execution context),可以理解为一个执行环境。与常见的浏览器执行环境不同,在这个环节中执行的所有异步任务都被称为 task ,zone 为这些 task 提供了一堆的钩子(hook),使得开发者可以很轻松的「监控」环境中所有的异步任务。
题外话:由于 angular 极力的推崇使用可观察对象(observable),如果完全的基于 observable 来开发应用,可以代替 zone 来实现追踪调用栈的功能,且性能还比使用 zone 会稍好一些。
// angular 在 v5.0.0-beta.8 起可以通过配置不使用 zone import { platformbrowser } from '@angular/platform-browser'; platformbrowser().bootstrapmodulefactory(appmodulengfactory, { ngzone: 'noop' });
覆盖浏览器默认机制
angular 在启动时会重写浏览器 low-level api,例如addeventlistener
,它是用于注册所有浏览器事件的浏览器函数,包括点击处理。angular 将替换addeventlistener
为与此等效的新版本:
// this is the new version of addeventlistener function addeventlistener(eventname, callback) { // call the real addeventlistener callrealaddeventlistener(eventname, function() { //first call the original callback callback(...); // and then run angular-specific functionality var changed = angular.runchangedetection(); if (changed) { angular.rerenderuipart(); } }); }
新的addeventlistener
为任何事件处理程序添加了更多功能:不仅调用了注册的回调,而且 angular 有机会运行更改检测并更新 ui。
支持浏览器异步 api
修补了以下常用浏览器机制以支持更改检测:
- 所有浏览器事件(单击、鼠标悬停、按键等)
settimeout()
和setinterval()
- ajax http 请求
事实上,zone.js 修补了许多其他浏览器 api,以透明地触发 angular 更改检测,例如 websockets。
这种机制的一个限制是,如果由于某种原因 zone.js 不支持的异步浏览器 api,则不会触发更改检测。例如,indexeddb 回调就是这种情况。
默认的变更检测机制是如何工作的?
每个 angular 组件都有一个关联的变更检测器,它是在应用程序启动时创建的。例如:
@component({
selector: 'todo-item',
template: `{{todo.owner.firstname}} - {{todo.description}}
- completed: {{todo.completed}}`
})
export class todoitem {
@input()
todo:todo;
@output()
toggle = new eventemitter