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 ...
随机推荐
- tensorflow函数/重要功能实现
一.基础函数 1.1 .tf.reduce_sum(input_tensor, axis) Computes the sum of elements across dimensions of a ...
- git 回退各种场景操作
在git的一般使用中,如果发现错误的将不想提交的文件add进入index之后,想回退取消,则可以使用命令:git reset HEAD <file>...,同时git add完毕之后,gi ...
- Object Detection with 10 lines of code - Image AI
To perform object detection using ImageAI, all you need to do is Install Python on your computer sys ...
- [SimplePlayer] 3. 视频帧同步
Frame Rate 帧率代表的是每一秒所播放的视频图像数目.通常,视频都会有固定的帧率,具体点地说是每一帧的时间间隔都是一样的,这种情况简称为CFR(Constant Frame Rate);另外一 ...
- 【XSY3139】预言家 数位DP NFA
题目描述 有一个定义在 \(\{0,1,2,3,4,5,6,7,8,9\}\) 上的合规表达式,包含三种基本的操作: 结合:\(E_1E_2\) 分配:\((E_1|E_2|\ldots|E_n),n ...
- Django ORM操作补充
操作补充 only 只取某些去除其他 defer 去除某些取其他 # 需求: 只取某n列 queryset=[ {},{}] models.User.objects.all().values( 'id ...
- python xpath学习
一.选取节点: 二.谓词: 注意:在scrapy中用xpath进行搜索时,如果使用相对路径,要加上.,如,不然搜索的是整个文档.
- 使用vue-cli创建vue项目
vue-cli是官方发布的vue.js项目脚手架工具,使用它可以快速创建vue项目,github地址:https://github.com/vuejs/vue-cli 1.安装vue-cli //设置 ...
- [物理学与PDEs]第2章第2节 粘性流体力学方程组 2.4 粘性热传导流体动力学方程组
粘性热传导流体动力学方程组: $$\beex \bea \cfrac{\p \rho}{\p t}+\Div(\rho{\bf u})&=0,\\ \rho \cfrac{\rd {\bf u ...
- 消息队列MQ对比
1.ActiveMQ 是Apache下的一个子项目. 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列.同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景.RabbitMQ.Z ...