什麼是變化監測
在使用Angular 進行開發中,我們常用到Angular 中的綁定-模型到視圖的輸入綁定、視圖到模型的輸出綁定以及視圖與模型的雙向綁定。而這些綁定的數值之所以能在視圖與模型之間保持同步,正是得益於Angular中的變化檢測。
簡單來說,變化偵測就是Angular 用來偵測視圖與模型之間綁定的值是否發生了改變,當偵測到模型中綁定的值改變時,則同步到視圖上,反之,當偵測到視圖上綁定的值發生改變時,則回呼對應的綁定函數。
變更監控的源頭
變更監測的關鍵在於如何最小粒度地監測到綁定的值是否發生了改變,那麼在什麼情況下會導致這些綁定的值發生變化呢?我們可以看一下我們常用的幾個場景:
Events: click/hover/...
@Component({ selector: 'demo-component', template: ` <h1 id="name">{{name}}</h1> <button (click)="changeName()">change name</button> ` }) export class DemoComponent { name: string = 'Tom'; changeName() { this.name = 'Jerry'; } }
我們在模板中透過插值表達式綁定了 name 屬性。當點擊change name按鈕
時,改變了 name 屬性的值,這時模板視圖顯示內容也改變了。
XHR/webSocket
@Component({ selector: 'demo-component', template: ` <h1 id="name">{{name}}</h1> ` }) export class DemoComponent implements OnInit { name: string = 'Tom'; constructor(public http: HttpClient) {} ngOnInit() { // 假设有这个./getNewName请求,返回一个新值'Jerry' this.http.get('./getNewName').subscribe((data: string) => { this.name = data; }); } }
我們在這個組件的ngOnInit 函數裡向伺服器端發送了一個Ajax 請求,當這個請求返回結果時,同樣會改變當前模板視圖上綁定的name 屬性的值。
Times: setTimeout/requestAnimationFrame
@Component({ selector: 'demo-component', template: ` <h1 id="name">{{name}}</h1> ` }) export class DemoComponent implements OnInit { name: string = 'Tom'; constructor() {} ngOnInit() { // 假设有这个./getNewName请求,返回一个新值'Jerry' setTimeout(() => { this.name = 'Jerry'; }, 1000); } }
我們在這個元件的ngOnInit函數裡透過設定一個定時任務,當定時任務執行時,同樣會改變當前視圖上綁定的name屬性的值。
總結
其實,我們不難發現上述三種情況都有一個共同點,就是這些導致綁定值改變的事件都是非同步發生的。
Angular並不是捕捉物件的變動,它採用的是在適當的時機去檢驗物件的值是否被改動,這個時機就是這些非同步事件的發生。
這個時機是由NgZone 這個服務去掌控的,它獲取到了整個應用的執行上下文,能夠對相關的非同步事件發生、完成或異常等進行捕獲,然後驅動Angular的變化監測機制執行。
變化監測的處理機制
透過上面的介紹,我們大致明白了變化檢測是如何被觸發的,那麼Angular 中的變化監測是如何執行的呢?
首先我們需要知道的是,對於每一個元件,都有一個對應的變化監測器;即每一個Component 都對應有一個changeDetector
,我們可以在Component 中透過依賴注入來取得到changeDetector
。
而我們的多個Component 是一個樹狀結構的組織,由於一個Component 對應一個changeDetector
,那麼changeDetector
之間同樣是一個樹狀結構的組織。
最後我們要記住的一點是,每次變化監測都是從 Component 樹根開始的。
舉例
子元件:
@Component({ selector: 'demo-child', template: ` <h1 id="title">{{title}}</h1> <p>{{paramOne}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { title: string = '子组件标题'; @Input() paramOne: any; // 输入属性1 @Input() paramTwo: any; // 输入属性2 }
父元件:
@Component({ selector: 'demo-parent', template: ` <h1 id="title">{{title}}</h1> <demo-child [paramOne]='paramOneVal' [paramTwo]='paramTwoVal'></demo-child> <button (click)="changeVal()">change name</button> ` }) export class DemoParentComponent { title: string = '父组件标题'; paramOneVal: any = '传递给paramOne的数据'; paramTwoVal: any = '传递给paramTwo的数据'; changeVal() { this.paramOneVal = '改变之后的传递给paramOne的数据'; } }
上面的程式碼中,DemoParentComponent 透過
當我們點擊DemoParentComponent 的button 時,會回調到changeVal 方法,然後會觸發變化監測的執行,變化監測流程如下:
首先變更偵測從DemoParentComponent開始:
偵測title 值是否發生了變化:沒有發生變化
偵測paramOneVal 值是否發生了變化:發生了變化(點擊按鈕呼叫changeVal()方法改變的)
檢測paramTwoVal 值是否發生了變化:沒有變化
然後變化檢測進入到葉子節點DemoChildComponent:
偵測title 值是否發生了改變:沒有發生變化
偵測paramOne 是否發生了變化:發生了改變(由於父元件的屬性paramOneVal發生了改變)
- ##檢測paramTwo 是否發生了改變:沒有改變 ##最後,因為DemoChildComponent 再也沒有了葉子節點,所以變化監測將更新DOM,同步視圖與模型之間的變化。
變化監測策略
學習了變化監測的處理機制之後,你可能會想,這機制未免也有點太簡單粗暴了吧,假如我的應用中有成百上千個Component,隨便一個Component 觸發了監測,那麼都需要從根節點到葉節點重新偵測一次。
別急,Angular 的開發團隊已經考慮到了這個問題,上述的偵測機制只是一種預設的偵測機制,Angular 也提供一個OnPush 的偵測機制(設定元資料屬性changeDetection: ChangeDetectionStrategy.OnPush )。
OnPush 与 Default 之间的差别:当检测到与子组件输入绑定的值没有发生改变时,变化检测就不会深入到子组件中去。
变化监测类 - ChangeDetectorRef
上面说到我们可以修改组件元数据属性 changeDetection 来修改组件的变化监测策略(ChangeDetectionStrategy.Default 或 ChangeDetectionStrategy.OnPush),除了这个,我们还可以使用 ChangeDetectorRef 来更加灵活的控制组件的变化监测。
Angular 在整个运行期间都会为每一个组件创建 ChangeDetectorRef 的实例,该实例提供了相关方法来手动管理变化监测。有了这个类,我们自己就可以自定义组件的变化监测策略了,如停止/启用变化监测或者按指定路径变化监测等等。
相关方法如下:
markForCheck():把根组件到该组件之间的这条路径标记起来,通知Angular在下次触发变化监测时必须检查这条路径上的组件。
detach():从变化监测树中分离变化监测器,该组件的变化监测器将不再执行变化监测,除非再次手动执行reattach()方法。
reattach():把分离的变化监测器重新安装上,使得该组件及其子组件都能执行变化监测。
detectChanges():手动触发执行该组件到各个子组件的一次变化监测。
使用方法也很简单,直接在组件中注入即可:
@Component({ selector: 'demo-parent', template: ` <h1 id="title">{{title}}</h1> ` }) export class DemoParentComponent implements OnInit { title: string = '组件标题'; constructor(public cdRef: ChangeDetectorRef) {} ngOnInit() { this.cdRef.detach(); // 停止组件的变化监测,看需求使用不同的方法 } }
相关推荐:
以上是Angular開發實務(五):深入解析變化監測的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE

Python和JavaScript在性能和效率方面的差異主要體現在:1)Python作為解釋型語言,運行速度較慢,但開發效率高,適合快速原型開發;2)JavaScript在瀏覽器中受限於單線程,但在Node.js中可利用多線程和異步I/O提升性能,兩者在實際項目中各有優勢。

JavaScript起源於1995年,由布蘭登·艾克創造,實現語言為C語言。 1.C語言為JavaScript提供了高性能和系統級編程能力。 2.JavaScript的內存管理和性能優化依賴於C語言。 3.C語言的跨平台特性幫助JavaScript在不同操作系統上高效運行。

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

Dreamweaver CS6
視覺化網頁開發工具

Dreamweaver Mac版
視覺化網頁開發工具

SublimeText3 Linux新版
SublimeText3 Linux最新版