最新网站域名ip查询,男女做那个全面视频网站,重庆关键词优化,模板网站会影响网站优化吗2019独角兽企业重金招聘Python工程师标准 在使用Angular进行开发中#xff0c;我们常用到Angular中的绑定——模型到视图的输入绑定、视图到模型的输出绑定以及视图与模型的双向绑定。而这些绑定的值之所以能在视图与模型之间保持同步#xff0c;正是得益于Ang… 2019独角兽企业重金招聘Python工程师标准 在使用Angular进行开发中我们常用到Angular中的绑定——模型到视图的输入绑定、视图到模型的输出绑定以及视图与模型的双向绑定。而这些绑定的值之所以能在视图与模型之间保持同步正是得益于Angular中的变化检测。 变化检测是什么 简单来说变化检测就是Angular用来检测视图与模型之间绑定的值是否发生了改变当检测到模型中绑定的值发生改变时则同步到视图上反之当检测到视图上绑定的值发生改变时则回调对应的绑定函数。 什么情况下会引起变化检测 变化检测的关键在于如何最小粒度地检测到绑定的值是否发生了改变那么在什么情况下会导致这些绑定的值发生变化呢我们可以看一下我们常用的几种场景 Component({
selector: my-app,
template:
h1{{name}}/h1
button (click)changeName()change name/button})
export class MyApp {
nameTom;
changeName(){
this.nameJerry
}
} 我们在视图上通过插值表达式绑定了MyApp中的name属性当点击按钮时改变了name属性的值这时就导致了绑定的值发生了变化。再来看另外一种场景 Component({
selector: my-app,
template: h1{{name}}/h1,
styleUrls: [./app.component.css]
})
export class MyApp implements OnInit{
nameTom;
constructor(private http:Http){}
ngOnInit(){
this.http.get(/contacts)
.map(resres.json)
.subscribe(namethis.namename);
}
} 我们在MyApp这个组件的生命周期钩子函数里向服务器端发送了一个Ajax请求当这个请求返回结果时同样会改变当前视图上绑定的name属性的值。类似的我们还可能设定一些定时任务这些定时任务也可能会改变与视图绑定的值 Component({
selector: my-app,
template: h1{{name}}/h1,
styleUrls: [./app.component.css]
})
export class MyApp implements OnInit{
nameTom;
constructor(private http:Http){}
ngOnInit(){
setTimeout((){
this.nameJerry
},1000);
}
} 其实我们不难发现上述三种情况都有一个共同点即这些导致绑定值发生改变的事件都是异步发生的。如果这些异步的事件在发生时能够通知到Angular框架那么Angular框架就能及时的检测到变化。 那么Angular框架如何才能获知到这些异步事件的发生呢我们不妨来看一看异步事件在JavaScript中执行的过程 左边表示将要运行的代码这里的stack表示JavaScript的运行栈而webApi则是浏览器中提供的一些JavaScript的APITaskQueue表示JavaScript中任务队列因为JavaScript是单线程的异步任务在任务队列中执行。 当上述代码在JavaScript中执行时首先func1 进入运行栈func1执行完毕后setTimeout进入运行栈执行setTimeout过程中将回调函数cb 加入到任务队列然后setTimeout出栈接着执行func2函数func2函数执行完毕时运行栈为空接着任务队列中cb 进入运行栈得到执行。可以看出异步任务首先会进入任务队列当运行栈中的同步任务都执行完毕时异步任务进入运行栈得到执行。如果这些异步的任务执行前与执行后能提供一些钩子函数通过这些钩子函数Angular便能获知异步任务的执行。 事实上Angular正是使用Zonejs(它描述JavaScript执行过程的上下文可以在异步任务之间进行持久性传递它类似于Java中的TLS)来做到的。Zonejs通过猴子补丁的方式对webApi中的一些异步任务的API在运行时进行替换替换后的API提供了一些钩子函数。 变化检测是个什么样的过程 通过上面的介绍我们大致明白了变化检测是如何被触发的那么Angular中的变化检测是如何执行的呢首先我们需要知道的是对于每一个组件都有一个对应的变化检测器即每一个Component都对应有一个changeDetector我们可以在Component中通过依赖注入来获取到changeDetector。而我们的多个Component是一个树状结构的组织由于一个Component对应一个changeDetector那么changeDetector之间同样是一个树状结构的组织。最后我们需要记住的一点是每次变化检测都是从树根开始的。 枯燥无味的理论到此结束下面通过一些例子来直观的感受一下。 Main.component.ts
import {Component} from angular/core;
import {Actor} from ./actor.model;
Component({
selector: main,
template:
h1MovieApp/h1
p{{ slogan}}/p
button typebutton (click)changeActorProperties()Change Actor Properties
/button
button typebutton (click)changeActorObject()
ChangeActorObject
/button
movie [title]title [actor]actor/movie
})export class MainComponent {
slogan: string Just movie information;
title: string Terminator 1;
actor: Actor new Actor(Arnold, Schwarzenegger);
changeActorProperties() {
this.actor.firstName Nicholas;
this.actor.lastName Cage;
}changeActorObject() {
this.actor new Actor(Bruce, Willis);
}
}Movie.component.ts
import {Component, Input} from angular/core;
import {Actor} from ./actor.model;
Component({
selector: movie,
styles: [div{border: 1px solid black}],
template:
div
h3{{ title}}/h3
p
labelActor:/label
span{{actor.firstName}} {{actor.lastName}}/span
/p
/div
})
export class MovieComponent {
Input() title: string;
Input() actor: Actor;} 上述代码中MainComponent通过movie/movie 标签嵌入了MovieComponent从树状结构上来说MainComponent是MovieComponent的根节点而MovieComponent是MainComponent的叶子节点。当我们点击MainComponent的第一个button时会回调到changeActorProperties方法然后会触发变化检测的执行。首先变化检测从MainComponent开始 检测slogan 值是否发生了变化没有发生变化 检测 title 值是否发生了变化没有发生变化 检测 actor 值是否发生了变化没有发生变化 你可能对于 actor的检测结果感到疑惑不是明明改变了actor的属性值吗实质上在对actor检测时只检测actor 本身的引用值是否发生了改变改变actor的属性值并未改变actor 本身的引用因此是没有发生变化。而当我们点击MainComponent的第二个button 重新new了一个 actor 这时变化检测才会检测到 actor发生了改变。 然后变化检测进入到叶子节点MovieComponent 检测title 值是否发生了改变没有发生变化 检测actor.firstName 是否发生了变化发生了改变 检测actor.lastName 是否发生了改变发生了改变 因为MovieComponent再也没有了叶子节点所以变化检测将更新DOM同步视图与模型之间的变化。 看到这里你可能会想这机制未免也有点太简单粗暴了吧假如我的应用中有成百上千个Component随便一个Component 触发了检测那么都需要从根节点到叶子节点重新检测一遍。别着急Angular 的开发团队已经考虑到了这个问题上述的检测机制只是一种默认的检测机制Angular还提供一种OnPush的检测机制还是同样的例子下面看一下OnPush检测机制是咋样的 Main.component.ts
import {Component, ChangeDetectionStrategy} from angular/core;
import {Actor} from ./actor.model;
Component({
selector: main,
template:
h1MovieApp/h1
p{{ slogan}}/p
button typebutton (click)changeActorProperties()
Change Actor Properties
/button
button typebutton (click)changeActorObject()
Change Actor Object
/button
movie [title]title [actor]actor/movie,
changeDetection:ChangeDetectionStrategy.OnPush
})export class MainComponent {
slogan: string Just movie information;
title: string Terminator 1;
actor: Actor new Actor(Arnold, Schwarzenegger);
changeActorProperties() {
this.actor.firstName Nicholas;
this.actor.lastName Cage;
}
changeActorObject() {
this.actor new Actor(Bruce, Willis);
}
} 与上面的代码相比只在Component中添加了 changeDetection:ChangeDetectionStrategy.OnPush 即将检测机制设置为OnPush。同样的当我们点击第一个button时将会发生如下变化检测 检测slogan 值是否发生了变化没有发生变化 检测 title 值是否发生了变化没有发生变化 检测 actor 值是否发生了变化没有发生变化 好变化检测到此结束不会再进入到 MovieComponent 中了。这正是OnPush与Default之间的差别当检测到与子组件输入绑定的值没有发生改变时变化检测就不会深入到子组件中去。那么当我们点击MainComponent中的第二个按钮时由于改变了actor本身而不是它的属性值那么就会检测到actor的变化进而继续进入到MovieComponent 进行变化检测。所以当你使用了OnPush检测机制时在修改一个绑定值的属性时要确保同时修改到了绑定值本身的引用。但是每次需要改变属性值的时候去new一个新的对象会使得代码很难看并且有时候你难以保证你一定记得这么做恩immutable.js 你值得拥有 另外一个问题就是当我们使用OnPush并且输入绑定的是一个Observable对象时怎么才能检测到当订阅的事件发生时引起的绑定的值的发生了改变呢比如下面这个组件 import {Component, Input, ChangeDetectionStrategy} from angular/core;
import {Observable} from rxjs;
Component({
selector: my-count,
template: span{{count}}/span,
changeDetection:ChangeDetectionStrategy.OnPush
})export class CountComponent {
Input() addItemStream: Observableany;
count0;
ngOnInit(){
this.addItemStream.subscribe((){
this.count;
});
}
} 输入绑定 addItemStream 是一个Observable对象Observable对象本身是不会变化的只有当订阅的事件到达时才会去修改count的值。如果使用OnPush 那么检测就不会进入到CountComponent。解决的办法很简单只需在修改count的值后做一个标记(markForCheck)那么变化检测就会沿着CountComponent所在的树枝进行变化检测。 import {Component, Input, ChangeDetectionStrategy, ChangeDetectorRef} from angular/core;
import {Observable} from rxjs;
Component({
selector: my-count,
template: span{{count}}/span,
changeDetection:ChangeDetectionStrategy.OnPush
})
export class CountComponent {
Input() addItemStream: Observableany;
count0;
constructor(private cd:ChangeDetectorRef){
}
ngOnInit(){
this.addItemStream.subscribe((){
this.count;
this.cd.markForCheck();
});
}
} 总结 总结来说Angular中变化检测器是树型结构的组织与组件树结构相对应默认情况下当一个组件引发了变化检测时检测是从树根开始一直检测到树节点。当你设置某个组件的检测策略是 OnPush 时如果该组件的输入绑定没有发生变化时那么检测就不会进入到该组件。当组件树变的很庞大时常用这种办法来提高应用的性能。 转载于:https://my.oschina.net/u/2285087/blog/1142820