加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Angular 2中的Zone

发布时间:2020-12-17 10:11:33 所属栏目:安全 来源:网络整理
导读:原文地址:http://blog.thoughtram.io//angular/2016/02/01/Zone-in-angular-2.html 在理解Zone这篇文章中,在我们的代码中通过构建一个分析异步操作的zone,来探讨Zone的力量。 我们了解到,Zone是一种使我们能够hook到异步任务的执行上下文,如果你还未读过

原文地址:http://blog.thoughtram.io//angular/2016/02/01/Zone-in-angular-2.html

在理解Zone这篇文章中,在我们的代码中通过构建一个分析异步操作的zone,来探讨Zone的力量。
我们了解到,Zone是一种使我们能够hook到异步任务的执行上下文,如果你还未读过那篇文章,我强烈建议你阅读,因为它是这篇文章的基础,在这篇文章中,我们将需要仔细看看Zone在Angular中扮演的角色。

Zone与Angular完美结合

事实上,Zone很好的解决了,在我们Angular应用中用来执行变化检测的问题。你有没有问自己,何时以及为什么Angular会进行变化检测?是什么告诉Angular “哥们,一个变化可能发生在我的应用中。你能查一下吗?”。

在我们深入这些问题前,让我们先考虑一下究竟是什么原因导致了我们应用的变化。或者更确切地说,有什么可以改变应用的状态。应用状态的改变是由三个因素引起:

Events - 使用事件,类似于click,change,input,submit,…
XMLHttpRequests - 例如。从远程服务获取数据时
Timers - setTimeout(),setInterval()
当然,这三个因素都有一些共同点。你能说出它吗?他们都是异步的。

为什么认为这是很重要的?因为我们发现这些是Angular实际有兴趣去更新视图的唯一情况。

假设我们有一个Angular 2组件,点击一个按钮时执行处理程序:

@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';
  }
}

如果你不熟悉的(click)语法,你可能需要阅读Angular 2模板语法,简单的说就是为这个button元素设置一个点击事件处理。

当组件的button被点击,changeName()被执行,从而将改变组件的name属性,由于我们希望这种变化在DOM被反映出来,Angular需要更新相应的视图绑定{{name}},很好,似乎是奇迹般地工作了。

另一个例子是,使用setTimeout()来更新name属性,注意,我们删除了button

@Component({
  selector: 'my-component',template: `
    <h3>We love {{name}}</h3>
  `
})
class MyComponent implements OnInit {

  name:string = 'thoughtram';

  ngOnInit() {
    setTimeout(() => {
      this.name = 'Angular';
    },1000);
  }
}

我们并没有特别的做什么来告诉的框架, 变化已经发生,没有ng-click,没有$timeout,$scope.$apply()

如果你已经阅读了理解Zone这篇文章,你知道这工作显然是因为Angular2充分利用了Zone,Zone猴子补丁了全局异步操作,如setTimeout()和addEventListener(),这就是为什么Angular可以很简单的知道什么时候去更新DOM.

事实上,每当VM执行完成会去告诉Angular进行变化检测,就是这么简单:

ObservableWrapper.subscribe(this.zone.onTurnDone,() => { this.zone.run(() => { this.tick(); }); }); tick() { // perform change detection this.changeDetectorRefs.forEach((detector) => { detector.detectChanges(); }); }

每当Angular zone发射出一个onTurnDone事件,它会运行一个任务执行整个应用的变化检测。如果你有兴趣了解Angular2变化检测是如何工作的,关注着吧,我们很快会发表另一篇文章。

等等。onTurnDone事件从哪里发射出来?这是不是默认Zone API的一部分?事实上,Angular引入了名为NgZone的自己的Zone.

Angular 2中的NgZone

NgZone基本上是一个Zone fork出来的,它继承了Zone的API,还添加了一些用来执行上下文额外功能,其中一件事是添加了下面这些我们可以订阅的自定义事件API,因为这些是observable流

onTurnStart() - 在Angular事件启动前通知订阅者,发射每一次是由Angular处理的浏览器任务。

onTurnDone() - 在Angular zone完成当前任务时立即通知订阅者

onEventDone() - 在完成onTurnDone()回调之后在VM事件之前立即通知订阅者, 用来测试验证应用程序状态。

如果”Observables”和”Streams”对于你来说是新的,你可能需要阅读Taking advantage of Observables in Angular 2

主要原因是Angular添加自己的事件发射器,而不是依靠beforeTask和afterTask回调,是为了跟踪定时器和其他微任务。它是非常棒的,使用Observables的API来处理这些事件。

运行代码在Angular Zone外

由于NgZone其实只是全局Zone的一个fork,Angular对于在Zone内需要或不需要执行变化检查,都具有完全的控制权,这为什么是有用的?因为我们并不总是希望Angular神奇地进行变化检测。

正如前面提到过,Zone几乎在任何浏览器的全局异步操作打上了猴子补丁。并且NgZone只是Zone fork出来的,当异步操作发生时就会通知框架进行变化检测,所以当类似于mousemove事件发生时,它也将引发变化检测。

每次鼠标被触发时,我们可能不希望进行变化检测,因为它会减慢我们的应用和结果,是非常糟糕的用户体验。

这就是为什么NgZone带有一个runOutsideAngular()API
,其执行在NgZone的父Zone的给定的任务,这将不发出一个onTurnDone事件,因此,不进行任何改变的检测。为了证明这是非常有用的功能,让我们来看看下面的代码:

@Component({
  selector: 'progress-bar',template: ` <h3>Progress: {{progress}}</h3> <button (click)="processWithinAngularZone()"> Process within Angular zone </button> `
})
class ProgressBar {

  progress: number = 0;

  constructor(private zone: NgZone) {}

  processWithinAngularZone() {
    this.progress = 0;
    this.increaseProgress(() => console.log('Done!')); } }

在这里没有什么特别的,有一个组件,其模板中的按钮被点击时,会调用processWithinAngularZone()方法。然而,这个方法调用increaseProgress()。让我们来看看这个方法:

increaseProgress(doneCallback: () => void) { this.progress += 1; console.log(`Current progress: ${this.progress}%`); if (this.progress < 100) { window.setTimeout(() => { this.increaseProgress(doneCallback); },10); } else { doneCallback(); } }

increaseProgress()每10毫秒调用1次自己,直到调用100次,一旦完成,给定的doneCallback将执行,请注意我们是如何使用的setTimeout()来增长progress值.

在浏览器运行此代码,基本上我们已经知道代码将如何展示,每一次setTimeout()调用,Angular会执行变化检测和更新视图,我们会看到每10毫秒progress被增长,当在Angular的区外运行这段代码将变得更有趣,让我们添加一个方法,就是这样。

processOutsideAngularZone() {
  this.progress = 0;
  this.zone.runOutsideAngular(() => { this.increaseProgress(() => { this.zone.run(() => { console.log('Outside Done!'); }); }); }); }

processOutsideAngularZone()也调用increaseProgress(),但这次使用runOutsideAngularZone(),它会导致在每次timeout后Angular不会通知执行变化检测,我们可以在组件里注入token为NgZone,来访问Angular zone.

progress增加时UI不会更新,然而,一旦increaseProgress()完成后,我们使用zone.run()在Angular zone 内运行另一个任务,这又导致Angular 来执行变化检测并更新视图,换句话说,我们不会看到progress不断增加,一旦完成我们只看到progress最后的值,在这里可以看到全部的代码

Zone 现在也被提议在TC39作为标准,也许是另一个理由让我们来仔细学习它

转自http://ng2.zai.io/topic/detail/news/6abcbce76e50662c

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读