成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Angular 2.x+ 臟檢查機(jī)制理解

W4n9Hu1 / 771人閱讀

摘要:策略減少檢測(cè)次數(shù)當(dāng)輸入屬性不變時(shí),可以跳過(guò)整個(gè)變更檢測(cè)子樹(shù)?,F(xiàn)在當(dāng)執(zhí)行更改檢測(cè)時(shí),它將從上到下進(jìn)行。并且一旦更改檢測(cè)運(yùn)行結(jié)束,它將恢復(fù)整個(gè)樹(shù)的狀態(tài)。

Angular 2.x+ 臟檢查機(jī)制理解

目前幾種主流的前端框架都已經(jīng)實(shí)現(xiàn)雙向綁定特性,但實(shí)現(xiàn)的方法各有不同:

發(fā)布者-訂閱者模式(backbone.js)

臟值檢查(angular.js)

數(shù)據(jù)劫持 + 發(fā)布者-訂閱者模式(vue.js)

下面我們就來(lái)了解一下 ng2.x+ 的版本中的臟檢查機(jī)制是如何運(yùn)行的。

什么是變化檢測(cè)
變化檢測(cè)(臟檢查)的基本任務(wù)是獲取程序內(nèi)部狀態(tài)的變化,并使其在用戶(hù)界面上以某種方式可見(jiàn),這種狀態(tài)的變化可以來(lái)自于 JavaScript 的任何數(shù)據(jù)結(jié)構(gòu),最終呈現(xiàn)為用戶(hù)界面中的段落、表單、鏈接或者按鈕等 DOM 對(duì)象。我們把輸入數(shù)據(jù)結(jié)構(gòu)并生成 DOM 結(jié)構(gòu)顯示給用戶(hù)的過(guò)程叫作渲染。

然而在程序運(yùn)行時(shí)發(fā)生變化情況比較復(fù)雜,我們需要確定模型中發(fā)生什么變化,以及什么地方需要更新 DOM 節(jié)點(diǎn)。操作 DOM 樹(shù)十分昂貴,所以我們不僅需要找出待更新的地方,還需要保持操作數(shù)盡可能小。這可能通過(guò)許多不同的方式來(lái)解決:比如我們可以簡(jiǎn)單的發(fā)起 http 請(qǐng)求并重新渲染整個(gè)頁(yè)面,或者可以區(qū)分 DOM 樹(shù)的新舊狀態(tài)并只重新渲染二者不同的部分(ReactJS 虛擬 DOM 的解決方案)。

什么會(huì)引起變化
什么時(shí)候會(huì)產(chǎn)生變化?
Angular 如何確知更新視圖的時(shí)機(jī)?
@Component({
  template: `
    

{{firstname}} {{lastname}}

` }) class MyApp { firstname:string = "Pascal"; lastname:string = "Precht"; changeName() { this.firstname = "Brad"; this.lastname = "Green"; } }
上面的組件只是顯示兩個(gè)屬性,并提供一個(gè)方法來(lái)改變他們(點(diǎn)擊模板中的按鈕),點(diǎn)擊這個(gè)特定按鈕的時(shí)刻即是應(yīng)用程序狀態(tài)發(fā)生改變的時(shí)刻,因?yàn)樗淖兘M件的屬性,這也是我們想要更新視圖的時(shí)刻。
@Component()
class ContactsApp implements OnInit{
  contacts:Contact[] = [];

  constructor(private http: Http) {}

  ngOnInit() {
    this.http.get("/contacts")
      .map(res => res.json())
      .subscribe(contacts => this.contacts = contacts);
  }
}
這個(gè)組件擁有一個(gè)聯(lián)系人列表,當(dāng)它初始化時(shí)發(fā)送一個(gè) http 請(qǐng)求,一旦這個(gè)請(qǐng)求返回列表就會(huì)被更新,此時(shí)我們的應(yīng)用程序狀態(tài)發(fā)生改變,并需要更新視圖。

基本上應(yīng)用程序狀態(tài)的改變可以由三類(lèi)活動(dòng)引起:

事件 - click, submit, ...

XHR - 從遠(yuǎn)程服務(wù)器獲取數(shù)據(jù)

定時(shí)器 - setTimeout, setInterval

上述活動(dòng)都是異步的,因此我們可以得出結(jié)論:每當(dāng)執(zhí)行一些異步操作時(shí),我們的應(yīng)用程序狀態(tài)可能發(fā)生改變,這時(shí)則需要 Angular 更新視圖。

Angular 在啟動(dòng)時(shí)會(huì)重寫(xiě)(通過(guò) Zone.js)部分底層瀏覽器 APIs 比如 addEventListener

// this is the new version of addEventListener
function addEventListener(eventName, callback) {
     // call the real addEventListener
     callRealAddEventListener(eventName, function() {
        // first call the original callback
        callback(...);     
        // and then run Angular-specific functionality
        var changed = angular2.runChangeDetection();
         if (changed) {
             angular2.reRenderUIPart();
         }
     });
}
誰(shuí)通知 Angular 更新視圖

Zone 負(fù)責(zé)通知 Angular 進(jìn)行視圖更新,Angular 封裝有 NgZone,簡(jiǎn)單來(lái)說(shuō),通過(guò) Angular 的部分源碼我們可以知道有一個(gè)叫作 ApplicationRef 的東西負(fù)責(zé)監(jiān)聽(tīng) NgZone 中的 onTurnDone 事件,每當(dāng)該事件觸發(fā)時(shí),它就執(zhí)行 trick 方法進(jìn)行變化檢測(cè)的基本工作。

// very simplified version of actual source
class ApplicationRef {
  changeDetectorRefs:ChangeDetectorRef[] = [];

  constructor(private zone: NgZone) {
    this.zone.onTurnDone
      .subscribe(() => this.zone.run(() => this.tick());
  }

  tick() {
    this.changeDetectorRefs
      .forEach((ref) => ref.detectChanges());
  }
}
變化檢測(cè)
首先我們需要注意的是在 Angular 中每個(gè)組件都有自己的變化檢測(cè)器,這使得我們可以對(duì)每個(gè)組件分別控制如何以及何時(shí)進(jìn)行變化檢測(cè)。

由于每個(gè)組件都有其自己的變化檢測(cè)器,即一個(gè) Angular 應(yīng)用程序由一個(gè)組件樹(shù)組成,所以邏輯結(jié)果就是我們也有一個(gè)變化檢測(cè)器樹(shù),這棵樹(shù)也可以看作是一個(gè)有向圖,數(shù)據(jù)總是從上到下流動(dòng)。

數(shù)據(jù)從上到下的原因是因?yàn)樽兓瘷z測(cè)也總是從上到下對(duì)每一個(gè)多帶帶的組件進(jìn)行,每一次從根組件開(kāi)始,單向數(shù)據(jù)流比循環(huán)臟檢查更可預(yù)測(cè),我們總是可以知道視圖中使用的數(shù)據(jù)來(lái)自哪里。

我們假設(shè)在組件樹(shù)的某個(gè)地方觸發(fā)一個(gè)事件,比如一個(gè)按鈕被點(diǎn)擊,zones 會(huì)進(jìn)行事件的處理并通知 Angular,然后變化檢測(cè)依次向下傳遞。
如何觸發(fā)變化檢測(cè)
一種方法是基于組件的生命周期鉤子:
ngAfterViewChecked() {
    if (this.callback && this.clicked) {
        console.log("changing status ...");
        this.callback(Math.random());
    }
}
在開(kāi)發(fā)模式下運(yùn)行 Angular 會(huì)在控制臺(tái)中得到一條錯(cuò)誤日志,生產(chǎn)模式下則不會(huì)拋出。
EXCEPTION: Expression "{{message}} in App@3:20" has changed after it was checked
另一種方法是手動(dòng)控制變化檢測(cè)的打開(kāi)/關(guān)閉,并手動(dòng)觸發(fā):
constructor(private ref: ChangeDetectorRef) {
    ref.detach();
    setInterval(() => {
      this.ref.detectChanges();
    }, 5000);
  }
改善的臟檢查
Angular 2.x+ 的數(shù)據(jù)流是自頂向下,從父組件向子組件的的單向流動(dòng),變化監(jiān)測(cè)樹(shù)與之相呼應(yīng),單項(xiàng)數(shù)據(jù)量保證變化監(jiān)測(cè)的高效性和可預(yù)測(cè)性。檢查父組件后,子組件可能會(huì)改變父組件中的數(shù)據(jù)使得父組件需要被再次檢查,這是不被推薦的數(shù)據(jù)處理方式,并且在開(kāi)發(fā)模式下這種情況會(huì)拋出異常 ExpressionChangedAfterItHasBeenCheckedError,在生產(chǎn)模式下不會(huì)報(bào)錯(cuò)但是臟檢查僅會(huì)執(zhí)行一次。

相比之下 1.x 的版本采用雙向數(shù)據(jù)流,為了使得數(shù)據(jù)最終趨向穩(wěn)定不得不多次檢查錯(cuò)綜復(fù)雜的數(shù)據(jù)流,性能提升就此可見(jiàn)一斑。

性能
默認(rèn)情況下,即使每次發(fā)生事件都需要檢查每個(gè)組件,Angular 速度仍然非???,它可以在幾毫秒內(nèi)執(zhí)行數(shù)十萬(wàn)次檢查,這主要是由于 Angular 可以生成 VM 友好的代碼。
更優(yōu)的變化檢測(cè)
Angular 每次都要檢查每個(gè)組件,因?yàn)槭录l(fā)生的原因也許是應(yīng)用程序狀態(tài)已經(jīng)改變,但是如果我們能夠告訴 Angular  只對(duì)那些改變狀態(tài)的應(yīng)用程序部分運(yùn)行變化檢測(cè),那不是很好嗎?

事實(shí)證明,有些數(shù)據(jù)結(jié)構(gòu)可以給我們什么時(shí)候發(fā)生變化的一些保證 - ImmutablesObservables

理解不可變
比如我們擁有一個(gè)組件 VCardApp 使用 v-card 作為子組件,其具有一個(gè)輸入屬性 vData,并且我們可以使用 changeData 方法改變 vData 對(duì)象的 name 屬性(并不會(huì)改變?cè)搶?duì)象的引用)。
@Component({
  template: ""
})

class VCardApp {
  constructor() {
    this.vData = {
      name: "Christoph Burgdorf",
      email: "christoph@thoughtram.io"
    }
  }

  changeData() {
    this.vData.name = "Pascal Precht";
  }
}
當(dāng)某些事件導(dǎo)致 changeData 執(zhí)行時(shí),vData.name 發(fā)生改變并傳遞至 v-card 中,v-card 組件的變化檢測(cè)器檢查給定的數(shù)據(jù)新 vData 是否與以前一樣,在數(shù)據(jù)引用未變但是其參數(shù)改變的情況下,Angular 也需要對(duì)該數(shù)據(jù)進(jìn)行變化監(jiān)測(cè)。

這就是 immutable 數(shù)據(jù)結(jié)構(gòu)發(fā)揮作用的地方。

[
How I optimized Minesweeper using Angular 2 and Immutable.js to make it insanely fast](https://www.jvandemo.com/how-...

不可變對(duì)象
Immutable 為我們提供不可變的對(duì)象:這意味著如果我們使用不可變的對(duì)象,并且想要對(duì)這樣的對(duì)象進(jìn)行更改,我們會(huì)得到一個(gè)新的引用(保證原始對(duì)象不變)。
var vData = someAPIForImmutables.create({
              name: "Pascal Precht"
            });

var vData2 = vData.set("name", "Christoph Burgdorf");

vData === vData2 // false
上述偽代碼即演示不可變對(duì)象的含義,其中 someAPIForImmutables 可以是我們想要用于不可變數(shù)據(jù)結(jié)構(gòu)的任何 API。
OnPush 策略減少檢測(cè)次數(shù)
當(dāng)輸入屬性不變時(shí),Angular可以跳過(guò)整個(gè)變更檢測(cè)子樹(shù)。如果我們?cè)?Angular 應(yīng)用程序中使用不可變對(duì)象,我們所需要做的就是告訴 Angular 組件可以跳過(guò)變化檢測(cè),如果它的輸入沒(méi)有改變的話(huà)。
@Component({
  template: `
    

{{vData.name}}

{{vData.email}} ` }) class VCardCmp { @Input() vData; }
正如我們所看到的,VCardCmp 只依賴(lài)于它的輸入屬性,我們可以告訴 Angular 跳過(guò)這個(gè)組件的子樹(shù)的變化檢測(cè),如果它的輸入沒(méi)有改變,通過(guò)設(shè)置變化檢測(cè)策略 OnPush 是這樣的:
@Component({
  template: `
    

{{vData.name}}

{{vData.email}} `, changeDetection: ChangeDetectionStrategy.OnPush }) class VCardCmp { @Input() vData; }

Angular OnPush Change Detection and Component Design - Avoid Common Pitfalls

Observables
與不可變的對(duì)象不同,當(dāng)進(jìn)行更改時(shí) Observables 不會(huì)給我們提供新的引用,而是發(fā)射我們可以訂閱的事件來(lái)對(duì)他們做出反應(yīng)。
@Component({
  template: "{{counter}}",
  changeDetection: ChangeDetectionStrategy.OnPush
})

class CartBadgeCmp {
  @Input() addItemStream:Observable;
  counter = 0;

  ngOnInit() {
    this.addItemStream.subscribe(() => {
      this.counter++; // application state changed
    })
  }
}
比如我們用購(gòu)物車(chē)建立一個(gè)電子商務(wù)應(yīng)用程序:每當(dāng)用戶(hù)將產(chǎn)品放入購(gòu)物車(chē)時(shí),我們需要在用戶(hù)界面中顯示一個(gè)小計(jì)數(shù)器,以便用戶(hù)可以看到購(gòu)物車(chē)中的產(chǎn)品數(shù)量。

該組件有一個(gè) counter 屬性和一個(gè)輸入屬性 addItemStream,當(dāng)產(chǎn)品被添加到購(gòu)物車(chē)時(shí),這是一個(gè)被觸發(fā)的事件流。另外,我們?cè)O(shè)置了變化檢測(cè)策略 OnPush,只有當(dāng)組件的輸入屬性發(fā)生變化時(shí),變化檢測(cè)才會(huì)執(zhí)行。

如前所述,引用 addItemStream 永遠(yuǎn)不會(huì)改變,所以組件的子樹(shù)從不執(zhí)行變更檢測(cè)。

當(dāng)整個(gè)樹(shù)被設(shè)置成 OnPush 后,我們?nèi)绾瓮ㄖ?Angular 需要對(duì)這個(gè)組件進(jìn)行變化檢測(cè)呢?正如我們所知,變化檢測(cè)總是從上到下執(zhí)行的,所以我們需要的是一種可以檢測(cè)樹(shù)的整個(gè)路徑到發(fā)生變化的組件的變化的方法。

我們可以通過(guò)依賴(lài)注入訪問(wèn)組件的 ChangeDetectorRef,這個(gè)注入來(lái)自一個(gè)叫做 markForCheck 的 API,它標(biāo)記從組件到根的路徑,以便下次更改檢測(cè)的運(yùn)行。

constructor(private cd: ChangeDetectorRef) {}
ngOnInit() {
    this.addItemStream.subscribe(() => {
      this.counter++; // application state changed
      this.cd.markForCheck(); // marks path
    })
  }
}
下面是在可觀察事件被觸發(fā)后,變化檢測(cè)開(kāi)始前。

現(xiàn)在當(dāng)執(zhí)行更改檢測(cè)時(shí),它將從上到下進(jìn)行。

并且一旦更改檢測(cè)運(yùn)行結(jié)束,它將恢復(fù) OnPush 整個(gè)樹(shù)的狀態(tài)。

TAKING ADVANTAGE OF OBSERVABLES IN ANGULAR

ANGULAR CHANGE DETECTION EXPLAINED
How does Angular Change Detection Really Work ?
Change And Its Detection In JavaScript Frameworks

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/83215.html

相關(guān)文章

  • Angular 1 深度解析:數(shù)據(jù)檢查angular 性能優(yōu)化

    摘要:通常寫(xiě)代碼時(shí)我們無(wú)需主動(dòng)調(diào)用或是因?yàn)樵谕獠繉?duì)我們的回調(diào)函數(shù)做了包裝。類(lèi)似的不只是這些事件回調(diào)函數(shù),還有等。常量依舊會(huì)重復(fù)檢查。會(huì)檢查中有沒(méi)有一個(gè)名為的成員。 TL;DR 臟檢查是一種模型到視圖的數(shù)據(jù)映射機(jī)制,由 $apply 或 $digest 觸發(fā)。 臟檢查的范圍是整個(gè)頁(yè)面,不受區(qū)域或組件劃分影響 使用盡量簡(jiǎn)單的綁定表達(dá)式提升臟檢查執(zhí)行速度 盡量減少頁(yè)面上綁定表達(dá)式的個(gè)數(shù)(單次綁定...

    fasss 評(píng)論0 收藏0
  • Angular 1 深度解析:數(shù)據(jù)檢查angular 性能優(yōu)化

    摘要:通常寫(xiě)代碼時(shí)我們無(wú)需主動(dòng)調(diào)用或是因?yàn)樵谕獠繉?duì)我們的回調(diào)函數(shù)做了包裝。類(lèi)似的不只是這些事件回調(diào)函數(shù),還有等。常量依舊會(huì)重復(fù)檢查。會(huì)檢查中有沒(méi)有一個(gè)名為的成員。 TL;DR 臟檢查是一種模型到視圖的數(shù)據(jù)映射機(jī)制,由 $apply 或 $digest 觸發(fā)。 臟檢查的范圍是整個(gè)頁(yè)面,不受區(qū)域或組件劃分影響 使用盡量簡(jiǎn)單的綁定表達(dá)式提升臟檢查執(zhí)行速度 盡量減少頁(yè)面上綁定表達(dá)式的個(gè)數(shù)(單次綁定...

    VioletJack 評(píng)論0 收藏0
  • Immutable & Redux in Angular Way

    摘要:來(lái)源于社區(qū),時(shí)至今日已經(jīng)基本成為的標(biāo)配了。部分很簡(jiǎn)單,要根據(jù)傳入的執(zhí)行不同的操作。當(dāng)性能遇到瓶頸時(shí)基本不會(huì)遇到,可以更改,保證傳入數(shù)據(jù)來(lái)提升性能。當(dāng)不再能滿(mǎn)足程序開(kāi)發(fā)的要求時(shí),可以嘗試使用進(jìn)行函數(shù)式編程。 Immutable & Redux in Angular Way 寫(xiě)在前面 AngularJS 1.x版本作為上一代MVVM的框架取得了巨大的成功,現(xiàn)在一提到Angular,哪怕是已...

    lunaticf 評(píng)論0 收藏0
  • angular2 檢查series1-Zone.js

    摘要:并不是真正的進(jìn)入,而是通過(guò)包裹的方式偽造執(zhí)行上下文,并通過(guò)鉤子函數(shù)方便的進(jìn)入執(zhí)行環(huán)境。如何使用運(yùn)行結(jié)果可以從上面的看到運(yùn)用提供的,鉤子函數(shù)方便的進(jìn)入了執(zhí)行的上下文,記錄了時(shí)間。我們還有個(gè)需求,需要因人而異的處理這些暴露的鉤子函數(shù)。 angular2 臟檢查總述 這系列文章將介紹angular2的臟值檢查是如何工作的?如何比ng1更高效?帶著上述問(wèn)題,讓我們一起來(lái)看看angular2這禽...

    0x584a 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<