angular 2+ 变化检测系列三(Zone.js在Angular中的应用)
在系列一中,我们提到Zone.js,Zones是一种执行上下文,它允许我们设置钩子函数在我们的异步任务的开始位置和结束位置,Angular正是利用了这一特性从而实现了变更检测。
Zones.js非常适合Angular
事实证明,Zones解决的问题非常适合Angular在我们的应用程序中执行变更检测所需的内容。你有没有问过自己Angular何时以及为何进行变化检测?什么时候告诉Angular: 兄弟,我的应用程序中可能发生了一个变化。你能检查一下吗?在我们深入研究这些问题之前,让我们首先考虑一下应用程序中实际导致这种变化的原因。或者更确切地说,在我们的应用程序中可以改变状应用程序状态更改由三种情况引起:
- Events - 用户事件比如
click,change,input,submit, … - XMLHttpRequests - 比如从远程服务器获取数据
- Timers -
setTimeout(),setInterval()
你可能发现了:这三种情况都是异步的.这是Angular实际上对更新视图感兴趣的唯一情况。假设我们有一个Angular组件,当单击一个按钮时它会执行一个处理程序
@Component({
selector: 'my-component',
template: `
<h3>We love {{name}}</h3>
<button (click)="changeName()">Change name</button>
`
})
class MyComponent {
name:string = 'thoughtram';
changeName() {
this.name = 'Angular';
}
}
单击组件的按钮时,将执行changeName(),这将更改组件的name属性。由于我们希望此更改也反映在DOM中,因此Angular将相应地更新视图绑定{{name}}。很好,这似乎神奇地工作。
另一个例子是使用setTimeout()更新name属性。请注意,我们删除了该按钮。
@Component({
selector: 'my-component',
template: `
<h3>We love {{name}}</h3>
`
})
class MyComponent implements OnInit {
name:string = 'thoughtram';
ngOnInit() {
setTimeout(() => {
this.name = 'Angular';
}, 1000);
}
}
我们没有一些特别操作,Angular自动帮我们做了变化检测.
实际上,告诉Angular在VM完成任务时执行更改检测的代码就像这样简单:
ObservableWrapper.subscribe(this.zone.onTurnDone, () => {
this.zone.run(() => {
this.tick();
});
});
tick() {
// perform change detection
this.changeDetectorRefs.forEach((detector) => {
detector.detectChanges();
});
}
每当Angular的区域发出onTurnDone事件时,它就会运行一个任务,对整个应用程序执行更改检测。但是等一下,onTurnDone事件发射器来自哪里?这不是默认Zone.js API的一部分,对吧?事实证明,Angular引入了自己的名为NgZone的区域。
Angular中的NgZone
NgZone基本上是一个分叉区域,它扩展了它的API并为其执行上下文添加了一些额外的功能。它添加到API中的一件事是我们可以订阅的以下一组自定义事件,因为它们是可观察的流:
- onTurnStart() - 在Angular事件开始之前通知订阅者。每个由Angular处理的浏览器任务发出一次事件。
- onTurnDone() - 在Angular的区域完成后处理当前事件队列以及从事件队列的任何微任务后立即通知订阅者。
- onEventDone() - 在结束VM事件之前,在最终的onTurnDone()回调之后立即通知订阅者。用于测试以验证应用程序状态。
Angular添加自己的事件发射器而不是依赖于beforeTask和afterTask回调的主要原因是它必须跟踪定时器和其他微任务。将Observable用作处理这些事件的API也很不错。
在Angular区域外运行代码
因为NgZone实际上是全局区域的一个分支,所以Angular可以完全控制代码什么时候在其区域内进行变更检测,什么时候不能.为什么这有用?好吧,事实证明我们并不总是希望Angular能够神奇地执行变化检测。
正如前面提到的那样,Zones几乎可以通过浏览器修补任何全局异步操作。由于NgZone只是该区域的一个分支,它通知框架在异步操作发生时执行变更检测,因此当mousemove事件触发时它也会触发变更检测。我们可能不希望每次触发mousemove时都执行更改检测,因为它会降低我们的应用程序速度并导致非常糟糕的用户体验。
这就是为什么NgZone带有一个API runOutsideAngular(),它在NgZone的父区域中执行给定任务,该区域不会发出onTurnDone事件,因此不会执行更改检测。为了演示这个有用的功能,我们来看看下面的代码:
@Component({
selector: 'ng-zone-demo',
template: `
<p>Progress: {{progress}}%</p>
<p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>
<button (click)="processWithinAngularZone()">Process within Angular zone</button>
<button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
`
})
export class NgZoneDemoComponent {
progress: number = 0;
label: string;
constructor(private _ngZone: NgZone) {}
// Loop inside the Angular zone
// so the UI DOES refresh after each setTimeout cycle
processWithinAngularZone() {
this.label = 'inside';
this.progress = 0;
this._increaseProgress(() => console.log('Inside Done!'));
}
// Loop outside of the Angular zone
// so the UI DOES NOT refresh after each setTimeout cycle
processOutsideOfAngularZone() {
this.label = 'outside';
this.progress = 0;
this._ngZone.runOutsideAngular(() => {
this._increaseProgress(() => {
// reenter the Angular zone and display done
this._ngZone.run(() => { console.log('Outside Done!') });
});
});
}
_increaseProgress(doneCallback: () => void) {
this.progress += 1;
console.log(`Current progress: ${this.progress}%`);
if (this.progress < 100) {
window.setTimeout(() => {
this._increaseProgress(doneCallback);
}, 10);
} else {
doneCallback();
}
}
}
angular 2+ 变化检测系列三(Zone.js在Angular中的应用)的更多相关文章
- angular 2+ 变化检测系列一(基础概念)
什么是变化检测? 变化检测的基本功能就是获取应用程序的内部状态(state),并且是将这种状态对用户界面保持可见.状态可以是javascript中的任何的数据结构,比如对象,数组,(数字,布尔,字符串 ...
- angular 2+ 变化检测系列二(检测策略)
我们将创建一个简单的MovieApp来显示有关一部电影的信息.这个应用程序将只包含两个组件:显示有关电影的信息的MovieComponent和包含执行某些操作按钮的电影引用的AppComponent. ...
- Angular开发实践(三):剖析Angular Component
Web Component 在介绍Angular Component之前,我们先简单了解下W3C Web Components 定义 W3C为统一组件化标准方式,提出Web Component的标准. ...
- zone.js - 暴力之美
在ng2的开发过程中,Angular团队为我们带来了一个新的库 – zone.js.zone.js的设计灵感来源于Dart语言,它描述JavaScript执行过程的上下文,可以在异步任务之间进行持久性 ...
- Zone.js 简介 & 抛砖引玉
Zone.js是angular团队参照NodeJS的Domain,Dart的Zone,为angular 2开发的核心组件. 一开始,我对Zone.js是拒绝的.我们知道类似的 Domain 模块,主要 ...
- Angular build Error:In this configuration Angular requires Zone.js
Angular cli 运行 build后打开生成的index.html报错:In this configuration Angular requires Zone.js 生成代码如下: ng bui ...
- Angular 个人深究(三)【由Input&Output引起的】
Angular 个人深究(三)[由Input&Output引起的] 注:最近项目在做别的事情,angular学习停滞了 1.Angular 中 @Input与@Output的使用 //test ...
- 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gulp专家
系列目录 前端构建大法 Gulp 系列 (一):为什么需要前端构建 前端构建大法 Gulp 系列 (二):为什么选择gulp 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gul ...
- Web 开发人员和设计师必读文章推荐【系列三十】
<Web 前端开发精华文章推荐>2014年第9期(总第30期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...
随机推荐
- ORM关于表那些事
一.. ORM表和表之间的关系 1. 一对多 --> 外键(ForeignKey) 2. 多对多 --> 另外一张关系表(ManyToManyField) 1. 三种方式 1. 自己建立第 ...
- luogu P1250 种树
我来总结一下最常用的两种办法 1.贪心 2.差分约束 那么我们先来讲,贪心版<种树> 大家可能知道有一个题和这个类似,那个是钉钉子而这个是种树 我们可以借用钉钉子的思路来想,首先这个是让你 ...
- docker_weave
安装 curl -L git.io/weave -o /usr/local/bin/weave chmod a+x /usr/local/bin/weave 启动 weave weave launch ...
- LoadRunner【第二篇】原理及使用流程
loadrunner工作原理 性能测试只关注底层数据,不关注业务,不关注客户端动作.所以,脚本运行正确不一定业务就正确(业务是否正确,如果是查询,我们可以通过检查点来判断:如果是增删改操作,可以看通过 ...
- GiBbook实用配置以及插件
GitBook可以在您的计算机上用于构建本地书籍,,可以本地预览 安装gitbook 环境要求: 安装GitBook,您的系统需要安装NodeJS(推荐v4.0.0及以上版本) NodeJS下载地址 ...
- Hadoop记录-JMX参数
Yarn metrics参数说明 获取Yarn jmx信息:curl -i http://xxx:8088/jmx Hadoop:service=ResourceManager,name=FSOpDu ...
- Run Configurations(Debug Configurations)->Arguments里填写program arguments和VM arguments
如图: 1.program arguments存储在String[] args里 2.VM arguments设置的是虚拟机的属性,是传给java虚拟机的.KV形式存储的,是可以通过System.ge ...
- Python系列之 - 前端总结
1. python序列化: 字符串 = json.dumps(对象) 对象->字符串 对象 = json.loads(字符串) 字符串->对象 Javascript: 字符串 = JSON ...
- 携程apollo系列-客户端集成
本文讲解如何在 Java 程序中集成 Apollo 配置, 主要涉及到一些基础用法. 对于一些高级用法, 比如如何加密/解密配置项 (可用于数据库密码配置), 如何动态切换数据源地址,如何动态切换日志 ...
- [Everyday Mathematics]20150305
设 $f\in C^2[0,1]$, $$\bex f(0)=-1,\quad f'(1)=3,\quad \int_0^1 xf''(x)\rd x=1. \eex$$ 试求 $f(1)$. 解答: ...