最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Angular系列之變化檢測(cè)(Change Detection)

 更新時(shí)間:2018年02月26日 14:08:50   作者:escaple_plan  
這篇文章主要介紹了詳解Angular系列之變化檢測(cè)(Change Detection),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

概述

簡(jiǎn)單來說變化檢測(cè)就是Angular用來檢測(cè)視圖與模型之間綁定的值是否發(fā)生了改變,當(dāng)檢測(cè)到模型中綁定的值發(fā)生改變時(shí),則同步到視圖上,反之,當(dāng)檢測(cè)到視圖上綁定的值發(fā)生改變時(shí),則回調(diào)對(duì)應(yīng)的綁定函數(shù)。

什么情況下會(huì)引起變化檢測(cè)?

總結(jié)起來, 主要有如下幾種情況可能也改變數(shù)據(jù):

  1. 用戶輸入操作,比如點(diǎn)擊,提交等
  2. 請(qǐng)求服務(wù)端數(shù)據(jù)(XHR)
  3. 定時(shí)事件,比如setTimeout,setInterval

上述三種情況都有一個(gè)共同點(diǎn),即這些導(dǎo)致綁定值發(fā)生改變的事件都是異步發(fā)生的。如果這些異步的事件在發(fā)生時(shí)能夠通知到Angular框架,那么Angular框架就能及時(shí)的檢測(cè)到變化。

左邊表示將要運(yùn)行的代碼,這里的stack表示Javascript的運(yùn)行棧,而webApi則是瀏覽器中提供的一些Javascript的API,TaskQueue表示Javascript中任務(wù)隊(duì)列,因?yàn)镴avascript是單線程的,異步任務(wù)在任務(wù)隊(duì)列中執(zhí)行。

具體來說,異步執(zhí)行的運(yùn)行機(jī)制如下:

  1. 所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。
  2. 主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之 中放置一個(gè)事件。
  3. 一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對(duì)應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
  4. 主線程不斷重復(fù)上面的第三步。

當(dāng)上述代碼在Javascript中執(zhí)行時(shí),首先func1 進(jìn)入運(yùn)行棧,func1執(zhí)行完畢后,setTimeout進(jìn)入運(yùn)行棧,執(zhí)行setTimeout過程中將回調(diào)函數(shù)cb 加入到任務(wù)隊(duì)列,然后setTimeout出棧,接著執(zhí)行func2函數(shù),func2函數(shù)執(zhí)行完畢時(shí),運(yùn)行棧為空,接著任務(wù)隊(duì)列中cb 進(jìn)入運(yùn)行棧得到執(zhí)行??梢钥闯霎惒饺蝿?wù)首先會(huì)進(jìn)入任務(wù)隊(duì)列,當(dāng)運(yùn)行棧中的同步任務(wù)都執(zhí)行完畢時(shí),異步任務(wù)進(jìn)入運(yùn)行棧得到執(zhí)行。如果這些異步的任務(wù)執(zhí)行前與執(zhí)行后能提供一些鉤子函數(shù),通過這些鉤子函數(shù),Angular便能獲知異步任務(wù)的執(zhí)行。

angular2 獲取變化通知

那么問題來了,angular2是如何知道數(shù)據(jù)發(fā)生了改變?又是如何知道需要修改DOM的位置,準(zhǔn)確的最小范圍的修改DOM呢?沒錯(cuò),盡可能小的范圍修改DOM,因?yàn)椴僮鱀OM對(duì)于性能來說可是一件奢侈品。

在AngularJS中是由代碼$scope.$apply()或者$scope.$digest觸發(fā),而Angular接入了ZoneJS,由它監(jiān)聽了Angular所有的異步事件。

ZoneJS是怎么做到的呢?

實(shí)際上Zone有一個(gè)叫猴子補(bǔ)丁的東西。在Zone.js運(yùn)行時(shí),就會(huì)為這些異步事件做一層代理包裹,也就是說Zone.js運(yùn)行后,調(diào)用setTimeout、addEventListener等瀏覽器異步事件時(shí),不再是調(diào)用原生的方法,而是被猴子補(bǔ)丁包裝過后的代理方法。代理里setup了鉤子函數(shù), 通過這些鉤子函數(shù), 可以方便的進(jìn)入異步任務(wù)執(zhí)行的上下文.

//以下是Zone.js啟動(dòng)時(shí)執(zhí)行邏輯的抽象代碼片段
function zoneAwareAddEventListener() {...}
function zoneAwareRemoveEventListener() {...}
function zoneAwarePromise() {...}
function patchTimeout() {...}
window.prototype.addEventListener=zoneAwareAddEventListener;
window.prototype.removeEventListener=zoneAwareRemoveEventListener;
window.prototype.promise = zoneAwarePromise;
window.prototype.setTimeout = patchTimeout;

變化檢測(cè)的過程

Angular的核心是組件化,組件的嵌套會(huì)使得最終形成一棵組件樹。Angular的變化檢測(cè)可以分組件進(jìn)行,每一個(gè)Component都對(duì)應(yīng)有一個(gè)changeDetector,我們可以在Component中通過依賴注入來獲取到changeDetector。而我們的多個(gè)Component是一個(gè)樹狀結(jié)構(gòu)的組織,由于一個(gè)Component對(duì)應(yīng)一個(gè)changeDetector,那么changeDetector之間同樣是一個(gè)樹狀結(jié)構(gòu)的組織.

另外,Angular的數(shù)據(jù)流是自頂而下,從父組件到子組件單向流動(dòng)。單向數(shù)據(jù)流向保證了高效、可預(yù)測(cè)的變化檢測(cè)。盡管檢查了父組件之后,子組件可能會(huì)改變父組件的數(shù)據(jù)使得父組件需要再次被檢查,這是不被推薦的數(shù)據(jù)處理方式。在開發(fā)模式下,Angular會(huì)進(jìn)行二次檢查,如果出現(xiàn)上述情況,二次檢查就會(huì)報(bào)錯(cuò):Expression Changed After It Has Been Checked Error。而在生產(chǎn)環(huán)境中,臟檢查只會(huì)執(zhí)行一次。

相比之下,AngularJS采用的是雙向數(shù)據(jù)流,錯(cuò)綜復(fù)雜的數(shù)據(jù)流使得它不得不多次檢查,使得數(shù)據(jù)最終趨向穩(wěn)定。理論上,數(shù)據(jù)可能永遠(yuǎn)不穩(wěn)定。AngularJS給出的策略是,臟檢查超過10次,就認(rèn)為程序有問題,不再進(jìn)行檢查。

變化檢測(cè)策略

Angular有兩種變化檢測(cè)策略。Default是Angular默認(rèn)的變化檢測(cè)策略,也就是上述提到的臟檢查,只要有值發(fā)生變化,就全部從父組件到所有子組件進(jìn)行檢查,。另一種更加高效的變化檢測(cè)方式:OnPush。OnPush策略,就是只有當(dāng)輸入數(shù)據(jù)(即@Input)的引用發(fā)生變化或者有事件觸發(fā)時(shí),組件才進(jìn)行變化檢測(cè)。

defalut 策略

main.component.ts

@Component({
 selector: 'app-root',
 template: `
 <h1>變更檢測(cè)策略</h1>
 <p>{{ slogan }}</p>
 <button type="button" (click)="changeStar()"> 改變明星屬性
 </button>
 <button type="button" (click)="changeStarObject()">
   改變明星對(duì)象
 </button>
 <movie [title]="title" [star]="star"></movie>`,
})
export class AppComponent {
 slogan: string = 'change detection';
 title: string = 'default 策略';
 star: Star = new Star('周', '杰倫');
 changeStar() {
  this.star.firstName = '吳';
  this.star.lastName = '彥祖';
 }
 changeStarObject() {
  this.star = new Star('劉', '德華');
 } 
}

movie.component.ts

@Component({
 selector: 'movie',
 styles: ['div {border: 1px solid black}'],
 template: `
<div>
<h3>{{ title }}</h3>
<p>
<label>Star:</label>
<span>{{star.firstName}} {{star.lastName}}</span>
</p>
</div>`,

})
export class MovieComponent {
 @Input() title: string;
 @Input() star;
}

上面代碼中, 當(dāng)點(diǎn)擊第一個(gè)按鈕改變明星屬性時(shí),依次對(duì)slogan, title, star三個(gè)屬性進(jìn)行檢測(cè), 此時(shí)三個(gè)屬性都沒有變化, star沒有發(fā)生變化,是因?yàn)閷?shí)質(zhì)上在對(duì)star檢測(cè)時(shí)只檢測(cè)star本身的引用值是否發(fā)生了改變,改變star的屬性值并未改變star本身的引用,因此是沒有發(fā)生變化。

而當(dāng)我們點(diǎn)擊第二個(gè)按鈕改變明星對(duì)象時(shí) ,重新new了一個(gè) star ,這時(shí)變化檢測(cè)才會(huì)檢測(cè)到 star發(fā)生了改變。

然后變化檢測(cè)進(jìn)入到子組件中,檢測(cè)到star.firstName和star.lastName發(fā)生了變化, 然后更新視圖.

OnPush策略

與上面代碼相比, 只在movie.component.ts中的@component中增加了一行代碼:

changeDetection:ChangeDetectionStrategy.OnPush
此時(shí), 當(dāng)點(diǎn)擊第一個(gè)按鈕時(shí), 檢測(cè)到star沒有發(fā)生變化, ok,變化檢測(cè)到此結(jié)束, 不會(huì)進(jìn)入到子組件中, 視圖不會(huì)發(fā)生變化.

當(dāng)點(diǎn)擊第二個(gè)按鈕時(shí),檢測(cè)到star發(fā)生了變化, 然后變化檢測(cè)進(jìn)入到子組件中,檢測(cè)到star.firstName和star.lastName發(fā)生了變化, 然后更新視圖.

所以,當(dāng)你使用了OnPush檢測(cè)機(jī)制時(shí),在修改一個(gè)綁定值的屬性時(shí),要確保同時(shí)修改到了綁定值本身的引用。但是每次需要改變屬性值的時(shí)候去new一個(gè)新的對(duì)象會(huì)很麻煩,immutable.js 你值得擁有!

變化檢測(cè)對(duì)象引用

通過引用變化檢測(cè)對(duì)象ChangeDetectorRef,可以手動(dòng)去操作變化檢測(cè)。我們可以在組件中的通過依賴注入的方式來獲取該對(duì)象:

constructor(
  private changeRef:ChangeDetectorRef
 ){}

變化檢測(cè)對(duì)象提供的方法有以下幾種:

  1. markForCheck() - 在組件的 metadata 中如果設(shè)置了 changeDetection:ChangeDetectionStrategy.OnPush 條件,那么變化檢測(cè)不會(huì)再次執(zhí)行,除非手動(dòng)調(diào)用該方法, 該方法的意思是在變化監(jiān)測(cè)時(shí)必須檢測(cè)該組件。
  2. detach() - 從變化檢測(cè)樹中分離變化檢測(cè)器,該組件的變化檢測(cè)器將不再執(zhí)行變化檢測(cè),除非手動(dòng)調(diào)用 reattach() 方法。
  3. reattach() - 重新添加已分離的變化檢測(cè)器,使得該組件及其子組件都能執(zhí)行變化檢測(cè)
  4. detectChanges() - 從該組件到各個(gè)子組件執(zhí)行一次變化檢測(cè)

OnPush策略下手動(dòng)發(fā)起變化檢測(cè)

組件中添加事件改變輸入屬性

在上面代碼movie.component.ts中修改如下

@Component({
 selector: 'movie',
 styles: ['div {border: 1px solid black}'],
 template: `
<div>
<h3>{{ title }}</h3>
<p>
<button (click)="changeStar()">點(diǎn)擊切換名字</button>    
<label>Star:</label>
<span>{{star.firstName}} {{star.lastName}}</span>
</p>
</div>`,
changeDetection:ChangeDetectionStrategy.OnPush
})
export class MovieComponent {
 constructor(
  private changeRef:ChangeDetectorRef
 ){}
 @Input() title: string;
 @Input() star;
 
 changeStar(){
  this.star.lastName = 'xjl';
 }
}

此時(shí)點(diǎn)擊按鈕切換名字時(shí),star更改如下

![圖片描述][3]

第二種就是上面講到的使用變化檢測(cè)對(duì)象中的 markForCheck()方法.

ngOnInit() {
  setInterval(() => {
   this.star.lastName = 'xjl';
   this.changeRef.markForCheck();
  }, 1000);
 }

輸入屬性為Observable

修改app.component.ts

@Component({
 selector: 'app-root',
 template: `
 <h1>變更檢測(cè)策略</h1>
 <p>{{ slogan }}</p>
 <button type="button" (click)="changeStar()"> 改變明星屬性
 </button>
 <button type="button" (click)="changeStarObject()">
   改變明星對(duì)象
 </button>
 <movie [title]="title" [star]="star" [addCount]="count"></movie>`,
})
export class AppComponent implements OnInit{
 slogan: string = 'change detection';
 title: string = 'OnPush 策略';
 star: Star = new Star('周', '杰倫');
 count:Observable<any>;

 ngOnInit(){
  this.count = Observable.timer(0, 1000)
 }
 changeStar() {
  this.star.firstName = '吳';
  this.star.lastName = '彥祖';
 }
 changeStarObject() {
  this.star = new Star('劉', '德華');
 } 
}

此時(shí),有兩種方式讓MovieComponent進(jìn)入檢測(cè),一種是使用變化檢測(cè)對(duì)象中的 markForCheck()方法.

ngOnInit() {
  this.addCount.subscribe(() => {
   this.count++;
   this.changeRef.markForCheck();
  })

另外一種是使用async pipe 管道

@Component({
 selector: 'movie',
 styles: ['div {border: 1px solid black}'],
 template: `
<div>
<h3>{{ title }}</h3>
<p>
<button (click)="changeStar()">點(diǎn)擊切換名字</button>    
<label>Star:</label>
<span>{{star.firstName}} {{star.lastName}}</span>
</p>
<p>{{addCount | async}}</p>
</div>`,
 changeDetection: ChangeDetectionStrategy.OnPush
})

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • AngularJS中的緩存使用

    AngularJS中的緩存使用

    一個(gè)緩存就是一個(gè)組件,它可以透明地儲(chǔ)存數(shù)據(jù),以便以后可以更快地服務(wù)于請(qǐng)求。這篇文章主要介紹了AngularJS中的緩存使用,有興趣的可以了解一下。
    2017-01-01
  • AngularJS基礎(chǔ) ng-dblclick 指令用法

    AngularJS基礎(chǔ) ng-dblclick 指令用法

    本文主要介紹AngularJS ng-dblclick 指令,這里對(duì)ng-dblclick基礎(chǔ)資料整理并詳細(xì)介紹,簡(jiǎn)單的代碼實(shí)例和實(shí)現(xiàn)效果,希望能幫助學(xué)習(xí)AngularJS的朋友
    2016-08-08
  • Angularjs根據(jù)json文件動(dòng)態(tài)生成路由狀態(tài)的實(shí)現(xiàn)方法

    Angularjs根據(jù)json文件動(dòng)態(tài)生成路由狀態(tài)的實(shí)現(xiàn)方法

    最近做項(xiàng)目遇到這樣一個(gè)新需求,就是需要根據(jù)json文件動(dòng)態(tài)生成路由狀態(tài),通過查閱相關(guān)資料實(shí)現(xiàn)了此功能,下面小編把問題總結(jié)分享到腳本之家平臺(tái)供大家參考
    2017-04-04
  • AngularJS深入探討scope,繼承結(jié)構(gòu),事件系統(tǒng)和生命周期

    AngularJS深入探討scope,繼承結(jié)構(gòu),事件系統(tǒng)和生命周期

    這篇文章主要介紹了AngularJS的scope,繼承結(jié)構(gòu),事件系統(tǒng)和生命周期,較為詳細(xì)的分析了scope的作用域、層次結(jié)構(gòu)、繼承及生命周期相關(guān)概念與使用技巧,需要的朋友可以參考下
    2016-11-11
  • angular6開發(fā)steps步驟條組件

    angular6開發(fā)steps步驟條組件

    這篇文章主要為大家詳細(xì)介紹了angular6開發(fā)steps步驟條組件的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • MODULE_INITIALIZER初始化Angular?懶加載模塊高級(jí)技巧

    MODULE_INITIALIZER初始化Angular?懶加載模塊高級(jí)技巧

    這篇文章主要為大家介紹了MODULE_INITIALIZER初始化Angular懶加載模塊高級(jí)技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 解決angular2在雙向數(shù)據(jù)綁定時(shí)[(ngModel)]無法使用的問題

    解決angular2在雙向數(shù)據(jù)綁定時(shí)[(ngModel)]無法使用的問題

    今天小編就為大家分享一篇解決angular2在雙向數(shù)據(jù)綁定時(shí)[(ngModel)]無法使用的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • 對(duì)Angular中單向數(shù)據(jù)流的深入理解

    對(duì)Angular中單向數(shù)據(jù)流的深入理解

    這篇文章主要給大家介紹了關(guān)于對(duì)Angular中單向數(shù)據(jù)流的深入理解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • 解析Angular 2+ 樣式綁定方式

    解析Angular 2+ 樣式綁定方式

    這篇文章主要介紹了解析Angular 2+ 樣式綁定方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • angular實(shí)現(xiàn)表單驗(yàn)證及提交功能

    angular實(shí)現(xiàn)表單驗(yàn)證及提交功能

    這篇文章主要為大家詳細(xì)介紹了angular實(shí)現(xiàn)表單驗(yàn)證及提交功能的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02

最新評(píng)論

普陀区| 永城市| 芒康县| 闻喜县| 察隅县| 新野县| 庆安县| 通城县| 安平县| 毕节市| 临沧市| 禹城市| 青神县| 密山市| 彭阳县| 分宜县| 额敏县| 新沂市| 常宁市| 商城县| 新沂市| 固安县| 乃东县| 柳河县| 手游| 和硕县| 四子王旗| 霍山县| 阿合奇县| 尼勒克县| 即墨市| 高要市| 石景山区| 扎兰屯市| 大埔县| 出国| 崇明县| 扶沟县| 广汉市| 和林格尔县| 潞西市|