国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Angular系列之變化檢測(Change Detection)

XGBCCC / 2356人閱讀

摘要:單向數據流向保證了高效可預測的變化檢測。變化檢測策略有兩種變化檢測策略。另一種更加高效的變化檢測方式。策略,就是只有當輸入數據即的引用發生變化或者有事件觸發時,組件才進行變化檢測。

概述

簡單來說變化檢測就是Angular用來檢測視圖與模型之間綁定的值是否發生了改變,當檢測到模型中綁定的值發生改變時,則同步到視圖上,反之,當檢測到視圖上綁定的值發生改變時,則回調對應的綁定函數。

什么情況下會引起變化檢測?

總結起來, 主要有如下幾種情況可能也改變數據:

用戶輸入操作,比如點擊,提交等

請求服務端數據(XHR)

定時事件,比如setTimeoutsetInterval

上述三種情況都有一個共同點,即這些導致綁定值發生改變的事件都是異步發生的。如果這些異步的事件在發生時能夠通知到Angular框架,那么Angular框架就能及時的檢測到變化。

左邊表示將要運行的代碼,這里的stack表示Javascript的運行棧,而webApi則是瀏覽器中提供的一些JavascriptAPITaskQueue表示Javascript中任務隊列,因為Javascript是單線程的,異步任務在任務隊列中執行。

具體來說,異步執行的運行機制如下:

所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。

主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之 中放置一個事件。

一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。

主線程不斷重復上面的第三步。

當上述代碼在Javascript中執行時,首先func1 進入運行棧,func1執行完畢后,setTimeout進入運行棧,執行setTimeout過程中將回調函數cb 加入到任務隊列,然后setTimeout出棧,接著執行func2函數,func2函數執行完畢時,運行棧為空,接著任務隊列中cb 進入運行棧得到執行。可以看出異步任務首先會進入任務隊列,當運行棧中的同步任務都執行完畢時,異步任務進入運行棧得到執行。如果這些異步的任務執行前與執行后能提供一些鉤子函數,通過這些鉤子函數,Angular便能獲知異步任務的執行。

angular2 獲取變化通知

那么問題來了,angular2是如何知道數據發生了改變?又是如何知道需要修改DOM的位置,準確的最小范圍的修改DOM呢?沒錯,盡可能小的范圍修改DOM,因為操作DOM對于性能來說可是一件奢侈品。

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

ZoneJS是怎么做到的呢?

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

//以下是Zone.js啟動時執行邏輯的抽象代碼片段
function zoneAwareAddEventListener() {...}
function zoneAwareRemoveEventListener() {...}
function zoneAwarePromise() {...}
function patchTimeout() {...}
window.prototype.addEventListener=zoneAwareAddEventListener;
window.prototype.removeEventListener=zoneAwareRemoveEventListener;
window.prototype.promise = zoneAwarePromise;
window.prototype.setTimeout = patchTimeout;
變化檢測的過程

Angular的核心是組件化,組件的嵌套會使得最終形成一棵組件樹。Angular的變化檢測可以分組件進行,每一個Component都對應有一個changeDetector,我們可以在Component中通過依賴注入來獲取到changeDetector。而我們的多個Component是一個樹狀結構的組織,由于一個Component對應一個changeDetector,那么changeDetector之間同樣是一個樹狀結構的組織.

另外,Angular的數據流是自頂而下,從父組件到子組件單向流動。單向數據流向保證了高效、可預測的變化檢測。盡管檢查了父組件之后,子組件可能會改變父組件的數據使得父組件需要再次被檢查,這是不被推薦的數據處理方式。在開發模式下,Angular會進行二次檢查,如果出現上述情況,二次檢查就會報錯:Expression Changed After It Has Been Checked Error。而在生產環境中,臟檢查只會執行一次。

相比之下,AngularJS采用的是雙向數據流,錯綜復雜的數據流使得它不得不多次檢查,使得數據最終趨向穩定。理論上,數據可能永遠不穩定。AngularJS給出的策略是,臟檢查超過10次,就認為程序有問題,不再進行檢查。

變化檢測策略

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

defalut 策略

main.component.ts

@Component({
  selector: "app-root",
  template: `
  

變更檢測策略

{{ slogan }}

`, }) 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: `

{{ title }}

{{star.firstName}} {{star.lastName}}

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

上面代碼中, 當點擊第一個按鈕改變明星屬性時,依次對slogan, title, star三個屬性進行檢測, 此時三個屬性都沒有變化, star沒有發生變化,是因為實質上在對star檢測時只檢測star本身的引用值是否發生了改變,改變star的屬性值并未改變star本身的引用,因此是沒有發生變化。

而當我們點擊第二個按鈕改變明星對象時 ,重新new了一個 star ,這時變化檢測才會檢測到 star發生了改變。

然后變化檢測進入到子組件中,檢測到star.firstNamestar.lastName發生了變化, 然后更新視圖.

OnPush策略

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

 changeDetection:ChangeDetectionStrategy.OnPush 

此時, 當點擊第一個按鈕時, 檢測到star沒有發生變化, ok,變化檢測到此結束, 不會進入到子組件中, 視圖不會發生變化.

當點擊第二個按鈕時,檢測到star發生了變化, 然后變化檢測進入到子組件中,檢測到star.firstNamestar.lastName發生了變化, 然后更新視圖.

所以,當你使用了OnPush檢測機制時,在修改一個綁定值的屬性時,要確保同時修改到了綁定值本身的引用。但是每次需要改變屬性值的時候去new一個新的對象會很麻煩,immutable.js 你值得擁有!

變化檢測對象引用

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

constructor(
    private changeRef:ChangeDetectorRef
  ){}

變化檢測對象提供的方法有以下幾種:

markForCheck() - 在組件的 metadata 中如果設置了 changeDetection:ChangeDetectionStrategy.OnPush 條件,那么變化檢測不會再次執行,除非手動調用該方法, 該方法的意思是在變化監測時必須檢測該組件。

detach() - 從變化檢測樹中分離變化檢測器,該組件的變化檢測器將不再執行變化檢測,除非手動調用 reattach() 方法。

reattach() - 重新添加已分離的變化檢測器,使得該組件及其子組件都能執行變化檢測

detectChanges() - 從該組件到各個子組件執行一次變化檢測

OnPush策略下手動發起變化檢測

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

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

@Component({
  selector: "movie",
  styles: ["div {border: 1px solid black}"],
  template: `

{{ title }}

{{star.firstName}} {{star.lastName}}

`, changeDetection:ChangeDetectionStrategy.OnPush }) export class MovieComponent { constructor( private changeRef:ChangeDetectorRef ){} @Input() title: string; @Input() star; changeStar(){ this.star.lastName = "xjl"; } }

此時點擊按鈕切換名字時,star更改如下

![圖片描述][3]

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

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

輸入屬性為Observable

修改app.component.ts

@Component({
  selector: "app-root",
  template: `
  

變更檢測策略

{{ slogan }}

`, }) export class AppComponent implements OnInit{ slogan: string = "change detection"; title: string = "OnPush 策略"; star: Star = new Star("周", "杰倫"); count:Observable; ngOnInit(){ this.count = Observable.timer(0, 1000) } changeStar() { this.star.firstName = "吳"; this.star.lastName = "彥祖"; } changeStarObject() { this.star = new Star("劉", "德華"); } }

此時,有兩種方式讓MovieComponent進入檢測,一種是使用變化檢測對象中的 markForCheck()方法.

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

另外一種是使用async pipe 管道

@Component({
  selector: "movie",
  styles: ["div {border: 1px solid black}"],
  template: `

{{ title }}

{{star.firstName}} {{star.lastName}}

{{addCount | async}}

`, changeDetection: ChangeDetectionStrategy.OnPush })

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85071.html

相關文章

  • 這5篇文章將使你成為一個Angular Change Detection專家。

    摘要:編寫工作首先介紹了一個稱為的內部組件表示,并解釋了變更檢測過程在視圖上運行。本文主要由兩部分組成第一部分探討錯誤產生的原因,第二部分提出可能的修正。它對我意義重大,它能幫助其他人看到這篇文章。 在過去的8個月里,我大部分空閑時間都是reverse-engineering Angular。我最感興趣的話題是變化檢測。我認為它是框架中最重要的部分,因為它負責像DOM更新、輸入綁定和查詢列表...

    Coly 評論0 收藏0
  • [譯] $digest 在 Angular 中重生

    摘要:但如果一個組件在生命周期鉤子里改變父組件屬性,卻是可以的,因為這個鉤子函數是在更新父組件屬性變化之前調用的注即第步,在第步之前調用。 原文鏈接:Angular.js’ $digest is reborn in the newer version of Angular showImg(https://segmentfault.com/img/remote/146000001468785...

    incredible 評論0 收藏0
  • Angular 2.x+ 臟檢查機制理解

    摘要:策略減少檢測次數當輸入屬性不變時,可以跳過整個變更檢測子樹。現在當執行更改檢測時,它將從上到下進行。并且一旦更改檢測運行結束,它將恢復整個樹的狀態。 Angular 2.x+ 臟檢查機制理解 目前幾種主流的前端框架都已經實現雙向綁定特性,但實現的方法各有不同: 發布者-訂閱者模式(backbone.js) 臟值檢查(angular.js) 數據劫持 + 發布者-訂閱者模式(vue.j...

    W4n9Hu1 評論0 收藏0
  • Change Detection And Batch Update

    摘要:如果我們不使用提供的事件系統定時器和,如在事件中進行數據更新時,我們需要手動調用。 前言 在傳統的WEB開發中,當與用戶或服務器發生交互時,需要我們手動獲取數據并更新DOM,這個過程是繁瑣的、易錯的。特別是當頁面功能過于復雜時,我們既要關注數據的變化,又要維護DOM的更新,這樣寫出來的代碼是很難維護的。新一代的框架或庫,例如Angular、React、Vue等等讓我們的關注點只在數據上...

    陳江龍 評論0 收藏0
  • Angular4 動態加載組件雜談

    摘要:最近接手了一個項目,客戶提出了一個高大上的需求要求只有一個主界面,所有組件通過來顯示。 最近接手了一個項目,客戶提出了一個高大上的需求:要求只有一個主界面,所有組件通過Tab來顯示。其實這個需求并不詭異,不喜歡界面跳轉的客戶都非常熱衷于這種展現形式。 好吧,客戶至上,搞定它!這種實現方式在傳統的HTML應用中,非常簡單,只是在這Angular4(以下簡稱ng)中,咋個弄呢? 我們先來了...

    testHs 評論0 收藏0

發表評論

0條評論

XGBCCC

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<