這篇文章主要介紹“Angular中的變化檢測實例分析”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Angular中的變化檢測實例分析”文章能幫助大家解決問題。
成都創(chuàng)新互聯(lián)公司擁有十多年成都網(wǎng)站建設(shè)工作經(jīng)驗,為各大企業(yè)提供網(wǎng)站設(shè)計制作、網(wǎng)站設(shè)計服務(wù),對于網(wǎng)頁設(shè)計、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、app軟件開發(fā)、wap網(wǎng)站建設(shè)(手機版網(wǎng)站建設(shè))、程序開發(fā)、網(wǎng)站優(yōu)化(SEO優(yōu)化)、微網(wǎng)站、主機域名等,憑借多年來在互聯(lián)網(wǎng)的打拼,我們在互聯(lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了很多網(wǎng)站制作、網(wǎng)站設(shè)計、網(wǎng)絡(luò)營銷經(jīng)驗,集策劃、開發(fā)、設(shè)計、營銷、管理等網(wǎng)站化運作于一體,具備承接各種規(guī)模類型的網(wǎng)站建設(shè)項目的能力。
變化檢測是前端框架中很有趣的一部分內(nèi)容,各個前端的框架也都有自己的一套方案,一般情況下我們不太需要過多的了解變化檢測,因為框架已經(jīng)幫我們完成了大部分的工作。不過隨著我們深入的使用框架,我們會發(fā)現(xiàn)我們很難避免的要去了解變化檢測,了解變化檢測可以幫助我們更好的理解框架、排查錯誤、進(jìn)行性能優(yōu)化等等。
簡單的來說,變化檢測就是通過檢測視圖與狀態(tài)之間的變化,在狀態(tài)發(fā)生了變化后,幫助我們更新視圖,這種將視圖和我們的數(shù)據(jù)同步的機制就叫變化檢測。
我們了解了什么是變化檢測,那何時觸發(fā)變化檢測呢?我們可以看看下面這兩個簡單的Demo
Demo1:
一個計數(shù)器組件,點擊按鈕Count會一直加 1
@Component({ selector: "app-counter", template: ` Count:{{ count }} <br /> <button (click)="increase()">Increase</button> `, }) export class CounterComponent { count = 0; constructor() {} increase() { this.count = this.count + 1; } }
Demo2:
一個Todo List的組件,通過Http獲取數(shù)據(jù)后渲染到頁面
@Component({ selector: "app-todos", template: ` <li *ngFor="let item of todos">{{ item.titme }}</li> `, }) export class TodosComponent implements OnInit { public todos: TodoItem[] = []; constructor(private http: HttpClient) {} ngOnInit() { this.http.get<TodoItem[]>("/api/todos").subscribe((todos: TodoItem[]) => { this.todos = todos; }); } }
從上面的兩個 Demo 中我們發(fā)現(xiàn),在兩種情況下觸發(fā)了變化檢測:
點擊事件發(fā)生時
通過 http 請求遠(yuǎn)程數(shù)據(jù)時
仔細(xì)思考下,這兩種觸發(fā)的方式有什么共同點呢? 我們發(fā)現(xiàn)這兩種方式都是異步操作,所以我們可以得出一個結(jié)論: 只要發(fā)生了異步操作,Angular 就會認(rèn)為有狀態(tài)可能發(fā)生變化了,然后就會進(jìn)行變化檢測。
這個時候可能大家會想到 setTimeout
setInterval
,是的,它們同樣也會觸發(fā)變化檢測。
@Component({ selector: "app-counter", template: ` Count:{{ count }} <br /> <button (click)="increase()">Increase</button> `, }) export class CounterComponent implements OnInit { count = 0; constructor() {} ngOnInit(){ setTimeout(()=>{ this.count= 10; }); } increase() { this.count = this.count + 1; } }
簡而言之,如果發(fā)生以下事件之一,Angular 將觸發(fā)變化檢測:
任何瀏覽器事件(click、keydown 等)
setInterval()
和 setTimeout()
HTTP 通過 XMLHttpRequest
進(jìn)行請求
剛才我們了解到,只要發(fā)生了異步操作,Angular 就會進(jìn)行變化檢測,那 Angular 又是如何訂閱到異步事件的狀態(tài),從而觸發(fā)變化檢測的呢?這里我們就要聊一聊 zone.js 了。
Zone.js
Zone.js 提供了一種稱為 ** 區(qū)域(Zone) ** 的機制,用于封裝和攔截瀏覽器中的異步活動、它還提供 異步生命周期的鉤子和 統(tǒng)一的異步錯誤處理機制。
Zone.js 是通過 Monkey Patching(猴子補丁)的方式來對瀏覽器中的常見方法和元素進(jìn)行攔截,例如 setTimeout
和 HTMLElement.prototype.onclick
。Angular 在啟動時會利用 zone.js 修補幾個低級瀏覽器 API,從而實現(xiàn)異步事件的捕獲,并在捕獲時間后調(diào)用變化檢測。
下面用一段簡化的代碼來模擬一下替換 setTimeout 的過程:
function setTimeoutPatch() { // 存儲原始的setTimeout var originSetTimeout = window['setTimeout']; // 對瀏覽器原生方法的包裹封裝 window.setTimeout = function () { return global['zone']['setTimeout'].apply(global.zone, arguments); }; // 創(chuàng)建包裹方法,提供給上面重寫后的setTimeout使用? Zone.prototype['setTimeout'] = function (fn, delay) { // 先調(diào)用原始方法 originSetTimeout.apply(window, arguments); // 執(zhí)行完原始方法后就可以做其他攔截后需要進(jìn)行的操作了 ... }; }
NgZone
Zone.js 提供了一個全局區(qū)域,可以被 fork 和擴展以進(jìn)一步封裝/隔離異步行為,Angular 通過創(chuàng)建一個fork并使用自己的行為擴展它,通常來說, 在 Angular APP 中,每個 Task 都會在 Angular 的 Zone 中運行,這個 Zone 被稱為 NgZone
。一個 Angular APP 中只存在一個 Angular Zone, 而變更檢測只會由運行于這個 ** **NgZone**
** 中的異步操作觸發(fā)。
簡單的理解就是: Angular 通過 Zone.js 創(chuàng)建了一個自己的區(qū)域并稱之為 NgZone,Angular 應(yīng)用中所有的異步操作都運行在這個區(qū)域中。
我們了解 Angular 的核心是 組件化,組件的嵌套會使得最終形成一棵 組件樹。
Angular 在生成組件的同時,還會為每一個組件生成一個變化檢測器 changeDetector
,用來記錄組件的數(shù)據(jù)變化狀態(tài),由于一個 Component 會對應(yīng)一個 changeDetector
,所以changeDetector
同樣也是一個樹狀結(jié)構(gòu)的組織。
在組件中我們可以通過注入 ChangeDetectorRef
來獲取組件的 changeDetector
@Component({ selector: "app-todos", ... }) export class TodosComponent{ constructor(cdr: ChangeDetectorRef) {} }
我們在創(chuàng)建一個 Angular 應(yīng)用 后,Angular 會同時創(chuàng)建一個 ApplicationRef
的實例,這個實例代表的就是我們當(dāng)前創(chuàng)建的這個 Angular 應(yīng)用的實例。 ApplicationRef
創(chuàng)建的同時,會訂閱 ngZone 中的 onMicrotaskEmpty
事件,在所有的微任務(wù)完成后調(diào)用所有的視圖的detectChanges()
來執(zhí)行變化檢測。
下是簡化的代碼:
class ApplicationRef { // ViewRef 是繼承于 ChangeDetectorRef 的 _views: ViewRef[] = []; constructor(private _zone: NgZone) { this._zone.onMicrotaskEmpty.subscribe({ next: () => { this._zone.run(() => { this.tick(); }); }, }); } // 執(zhí)行變化檢測 tick() { for (let view of this._views) { view.detectChanges(); } } }
單向數(shù)據(jù)流
什么是單向數(shù)據(jù)流?
剛才我們說了每次觸發(fā)變化檢測,都會從根組件開始,沿著整棵組件樹從上到下的執(zhí)行每個組件的變更檢測,默認(rèn)情況下,直到最后一個葉子 Component 組件完成變更檢測達(dá)到穩(wěn)定狀態(tài)。在這個過程中,一但父組件完成變更檢測以后,在下一次事件觸發(fā)變更檢測之前,它的子孫組件都不允許去更改父組件的變化檢測相關(guān)屬性狀態(tài)的,這就是單向數(shù)據(jù)流。
我們看一個示例:
@Component({ selector: "app-parent", template: ` {{ title }} <app-child></app-child> `, }) export class ParentComponent { title = "我的父組件"; } @Component({ selector: "app-child", template: ``, }) export class ChildComponent implements AfterViewInit { constructor(private parent: ParentComponent) {} ngAfterViewInit(): void { this.parent.title = "被修改的標(biāo)題"; } }
為什么出現(xiàn)這個錯誤呢?
這是因為我們違反了單向數(shù)據(jù)流,ParentComponent 完成變化檢測達(dá)到穩(wěn)定狀態(tài)后,ChildComponent 又改變了 ParentComponent 的數(shù)據(jù)使得 ParentComponent 需要再次被檢查,這是不被推薦的數(shù)據(jù)處理方式。在開發(fā)模式下,Angular 會進(jìn)行二次檢查,如果出現(xiàn)上述情況,二次檢查就會報錯: ExpressionChangedAfterItHasBeenCheckedError ,在生產(chǎn)環(huán)境中,則只會執(zhí)行一次檢查。
并不是在所有的生命周期去調(diào)用都會報錯,我們把剛才的示例修改一下:
@Component({ selector: "app-child", template: ``, }) export class ChildComponent implements OnInit { constructor(private parent: ParentComponent) {} ngOnInit(): void { this.parent.title = "被修改的標(biāo)題"; } }
修改后的代碼運行正常,這是為什么呢?這里要說一下Angular檢測執(zhí)行的順序:
更新所有子子組件綁定的屬性
調(diào)用所有子組件生命周期的鉤子 OnChanges, OnInit, DoCheck ,AfterContentInit
更新當(dāng)前組件的DOM
調(diào)用子組件的變換檢測
調(diào)用所有子組件的生命周期鉤子 ngAfterViewInit
ngAfterViewInit
是在變化檢測之后執(zhí)行的,在執(zhí)行變化檢測后我們更改了父組件的數(shù)據(jù),在Angular執(zhí)行開發(fā)模式下的第二次檢查時,發(fā)現(xiàn)與上一次的值不一致,所以報錯,而ngOnInit
的執(zhí)行在變化檢測之前,所以一切正常。
這里提一下AngularJS,AngularJS采用的是雙向數(shù)據(jù)流,錯綜復(fù)雜的數(shù)據(jù)流使得它不得不多次檢查,使得數(shù)據(jù)最終趨向穩(wěn)定。理論上,數(shù)據(jù)可能永遠(yuǎn)不穩(wěn)定。AngularJS的策略是,臟檢查超過10次,就認(rèn)為程序有問題,不再進(jìn)行檢查。
剛才我們聊了變化檢測的工作流程,接下來我想說的是變化檢測的性能, 默認(rèn)情況下,當(dāng)我們的組件中某個值發(fā)生了變化觸發(fā)了變化檢測,那么Angular會從上往下檢查所有的組件。不過Angular對每個組件進(jìn)行更改檢測的速度非常快,因為它可以使用 內(nèi)聯(lián)緩存 在幾毫秒內(nèi)執(zhí)行數(shù)千次檢查,其中內(nèi)聯(lián)緩存可生成對 VM 友好代碼。
盡管 Angular 進(jìn)行了大量優(yōu)化,但是遇到了大型應(yīng)用,變化檢測的性能仍然會下降,所以我們還需要用一些其他的方式來優(yōu)化我們的應(yīng)用。
Angular 提供了兩種運行變更檢測的策略:
Default
OnPush
Default 策略
默認(rèn)情況下,Angular 使用 ChangeDetectionStrategy.Default
變更檢測策略,每次事件觸發(fā)變化檢測(如用戶事件、計時器、XHR、promise 等)時,此默認(rèn)策略都會從上到下檢查組件樹中的每個組件。這種對組件的依賴關(guān)系不做任何假設(shè)的保守檢查方式稱為 臟檢查,這種策略在我們應(yīng)用組件過多時會對我們的應(yīng)用產(chǎn)生性能的影響。
OnPush 策略
Angular 還提供了一種 OnPush
策略,我們可以修改組件裝飾器的 changeDetection
來更改變化檢測的策略
@Component({ selector: 'app-demo', // 設(shè)置變化檢測的策略 changeDetection: ChangeDetectionStrategy.OnPush, template: ... }) export class DemoComponent { ... }
設(shè)置為 OnPush 策略后,Angular 每次觸發(fā)變化檢測后會跳過該組件和該組件的所以子組件變化檢測
OnPush模式下變化檢測流程
在 OnPush
策略下,只有以下這幾種情況才會觸發(fā)組件的變化檢測:
輸入值(@Input)更改
當(dāng)前組件或子組件之一觸發(fā)了事件
手動觸發(fā)變化檢測
使用 async 管道后, observable 值發(fā)生了變化
在默認(rèn)的變更檢測策略中,Angular 將在 @Input()
數(shù)據(jù)發(fā)生更改或修改時執(zhí)行變化檢測,使用該 OnPush
時,傳入 @Input()
的值 必須是一個新的引用才會觸發(fā)變化檢測。
JavaScript有兩種數(shù)據(jù)類型,值類型和引用類型,值類型包括:number、string、boolean、null、undefined,引用類型包括:Object、Arrary、Function,值類型每次賦值都會分配新的空間,而引用類型比如Object,直接修改屬性是引用是不會發(fā)生變化的,只有賦一個新的對象才會改變引用。
var a= 1; var b = a; b = 2; console.log(a==b); // false var obj1 = {a:1}; var obj2 = obj1; obj2.a = 2; console.log(obj1); // {a:2} console.log(obj1 === obj2); //true obj2= {...obj1}; console.log(obj1 === obj2); //false
如果 OnPush
組件或其子組件之一觸發(fā)事件,例如 click,則將觸發(fā)變化檢測(針對組件樹中的所有組件)。
需要注意的是在 OnPush
策略中,以下操作不會觸發(fā)變化檢測:
setTimeout()
setInterval()
Promise.resolve().then()
this.http.get('...').subscribe()
有三種手動觸發(fā)更改檢測的方法:
**detectChanges(): ** 它會觸發(fā)當(dāng)前組件和子組件的變化檢測
markForCheck():它不會觸發(fā)變化檢測,但是會把當(dāng)前的OnPush組件和所以的父組件為OnPush的組件 ** 標(biāo)記為需要檢測狀態(tài)** ,在當(dāng)前或者下一個變化檢測周期進(jìn)行檢測
ApplicationRef.tick(): 它會根據(jù)組件的變化檢測策略,觸發(fā)整個應(yīng)用程序的更改檢測
可以通過 在線Demo ,更直觀的了解這幾種觸發(fā)變化檢測的方式
內(nèi)置的 AsyncPipe
訂閱一個 observable 并返回它發(fā)出的最新值。
每次發(fā)出新值時的內(nèi)部 AsyncPipe
調(diào)用 markForCheck
private _updateLatestValue(async: any, value: Object): void { if (async === this._obj) { this._latestValue = value; this._ref.markForCheck(); } }
剛才我們聊了變化檢測的策略,我們可以使用
OnPush
的策略來優(yōu)化我們的應(yīng)用,那么這就夠了嗎? 在我們實際的開發(fā)中還會有很多的場景,我們需要通過一些其他的方式來繼續(xù)優(yōu)化我們的應(yīng)用。
場景1:
假如我們在實現(xiàn)一個回車搜索的功能:
@Component({ selector: "app-enter", template: `<input #input type="text" />`, }) export class EnterComponent implements AfterViewInit { @ViewChild("input", { read: ElementRef }) private inputElementRef: any; constructor() {} ngAfterViewInit(): void { this.inputElementRef.nativeElement.addEventListener( "keydown", (event: KeyboardEvent) => { const keyCode = event.which || event.keyCode; if (keyCode === 13) { this.search(); } } ); } search() { // ... } }
大家從上面的示例中可以發(fā)現(xiàn)什么問題呢?
我們知道事件會觸發(fā)Angular的變化檢測,在示例中綁定 keydown 事件后,每一次鍵盤輸入都會觸發(fā)變化檢測,而這些變化檢測大多數(shù)都是多余的檢測,只有當(dāng)按鍵為 Enter 時,才需要真正的進(jìn)行變化檢測。
在這種情況下,我們就可以利用 NgZone.runOutsideAngular()
來減少變化檢測的次數(shù)。
@Directive({ selector: '[enter]' }) export class ThyEnterDirective implements OnInit { @Output() enter = new EventEmitter(); constructor(private ngZone: NgZone, private elementRef: ElementRef<HTMLElement>) {} ngOnInit(): void { // 包裹代碼將運行在Zone區(qū)域之外 this.ngZone.runOutsideAngular(() => { this.elementRef.nativeElement.addEventListener('keydown', (event: KeyboardEvent) => { const keyCode = event.which || event.keyCode; if (keyCode === 13) { this.ngZone.run(() => { this.enter.emit(event); }); } }); }); } }
場景2:
假如我們使用 WebSocket 將大量數(shù)據(jù)從后端推送到前端,則相應(yīng)的前端組件應(yīng)僅每 10 秒更新一次。在這種情況下,我們可以通過調(diào)用 detach()
和手動觸發(fā)它來停用更改檢測detectChanges()
:
constructor(private cdr: ChangeDetectorRef) { cdr.detach(); // 停用變化檢測 setInterval(() => { this.cdr.detectChanges(); // 手動觸發(fā)變化檢測 }, 10 * 1000); }
當(dāng)然使用 ngZone.runOutsideAngular()
也可以處理這種場景。
之前我們說了Angular 可以自動幫我們進(jìn)行變化檢測,這主要是基于Zone.js來實現(xiàn),那么很多人潛意識會任務(wù)Zone.js 就是 Angular 是一部分,Angular的 應(yīng)用程序必須基于Zone.js,其實不然,如果我們對應(yīng)用有極高的性能要求時,我們可以選擇移除 Zone.js,移除Zone.js 將會提升應(yīng)用的性能和打包的體積,不過帶來的后果就是我們需要主要去調(diào)用變化檢測。
如何移除 Zone.js?
手動調(diào)用變化檢測
在 Ivy 之后,我們有一些新的API可以更方便的調(diào)用變化檢測
**?markDirty: ** 標(biāo)記一個組件為 dirty 狀態(tài) (需要重新渲染) 并將在未來某個時間點安排一個變更檢測
?detectChanges:因為某些效率方面的原因,內(nèi)部文檔不推薦使用 ?detectChanges
而推薦使用 ?markDirty
, ?detectChanges
會觸發(fā)組件以子組件的變更檢測。
移除后的性能
移除Zone.js后變化檢測由應(yīng)用自己來控制,極大的減少了不必要的變化檢測次數(shù),同時打包后的提及也減少了 36k
移除前:
移除后:
組件綁定
我們先來看一個組件綁定的例子:
按我們正常開發(fā)組件的想法,當(dāng)看到這個示例的時候一定認(rèn)為這個Case是Ok的,但是在運行測試后我們發(fā)現(xiàn)這個Case失敗了。
在生產(chǎn)環(huán)境中,當(dāng) Angular 創(chuàng)建一個組件,就會自動進(jìn)行變更檢測。 但是在測試中,**TestBed.createComponent()**
并不會進(jìn)行變化檢測,需要我們手動觸發(fā)。
修改一下上面的Case:
origin-url0.00KB
origin-url0.00KB
從上面的示例中可以了解到,我們必須通過調(diào)用 fixture.detectChanges()
來告訴 TestBed 執(zhí)行數(shù)據(jù)綁定。
如果我們在測試中動態(tài)改變了綁定值,同樣也需要調(diào)用 fixture.detectChanges()
。
it("should update title", () => { component.title = 'Test Title'; fixture.detectChanges(); const h2 = fixture.nativeElement.querySelector("h2"); expect(h2.textContent).toContain('Test Title'); });
自動變更檢測
我們發(fā)現(xiàn)寫測試過程中需要頻繁的調(diào)用 fixture.detectChanges()
,可能會覺得比較繁瑣,那 Angular 可不可以在測試環(huán)境中自動運行變化檢測呢?
我們可以通過配置 ComponentFixtureAutoDetect
來實現(xiàn)
TestBed.configureTestingModule({ declarations: [ BannerComponent ], providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] });
然后再回頭看看剛才的示例:
上面的示例我們并沒有調(diào)用 fixture.detectChanges()
,但是測試依然通過了,這是因為我們開啟了自動變化檢測。
再看一個示例:
上面的示例中,我們在測試代碼中動態(tài)修改了 title 的值,測試運行失敗,這是因為 Angular 并不知道測試改變了組件, ComponentFixtureAutoDetect
只對異步操作進(jìn)行自動變化檢測,例如 Promise、setTimeout、click 等DOM事件等,如果我們手動更改了綁定值,我們依然還需要調(diào)用 fixture.detectChanges()
來執(zhí)行變化檢測。
常見的坑
上面這個示例,綁定值修改后調(diào)用了 fixture.detectChanges()
, 但是運行測試后仍然報錯,這是為什么呢?
查看Angular源碼后我們發(fā)現(xiàn) ** ngModel 的值是通過異步更新的** ,執(zhí)行fixture.detectChanges()
后雖然觸發(fā)了變化檢測,但是值還并未修改成功。
修改一下測試:
修改后我們將斷言包裹在了 fixture.whenStable()
中,然后測試通過,那 whenStable()
是什么呢?
whenStable(): Promise : 當(dāng)夾具穩(wěn)定時解析的承諾 當(dāng)事件已觸發(fā)異步活動或異步變更檢測后,可用此方法繼續(xù)執(zhí)行測試。
當(dāng)然除了用 fixture.whenStable()
我們也可以用 tick()
來解決這個問題
tick() :為 fakeAsync Zone 中的計時器模擬異步時間流逝 在此函數(shù)開始時以及執(zhí)行任何計時器回調(diào)之后,微任務(wù)隊列就會耗盡
上面這個示例,我們在修改屬性后調(diào)用了 fixture.detectChanges()
,但是測試未通過,這是為什么呢?我們發(fā)現(xiàn)這個示例與第一個示例唯一的區(qū)別就是這個組件是一個 OnPush
組件,之前我們說過默認(rèn)變化檢測會跳過 OnPush
組件的,只有在特定的幾種情況下才會觸發(fā)變化檢測的,遇到這種情況如何解決呢?
我們可以手動獲取組件的 ChangeDetectorRef
來主動觸發(fā)變化檢測。
虛擬DOM與增量DOM
Angular Ivy 是一個新的 Angular 渲染器,它與我們在主流框架中看到的任何東西都截然不同,因為它使用增量 DOM。 增量DOM是什么呢?它與虛擬Dom有什么不同呢?
虛擬 DOM
首先說一下虛擬DOM,我們要了解在瀏覽器中,直接操作Dom是十分損耗性能的,而虛擬DOM 的主要概念是將 UI的虛擬表示保存在內(nèi)存中,通過 Diff 操作對比當(dāng)前內(nèi)存和上次內(nèi)存中視圖的差異,從而減少不必要的Dom操作,只針對差異的Dom進(jìn)行更改。
虛擬DOM執(zhí)行流程:
當(dāng) UI 發(fā)生變化時,將整個 UI 渲染到 Virtual DOM 中。
計算先前和當(dāng)前虛擬 DOM 表示之間的差異。
使用更改更新真實的 DOM。
虛擬 DOM 的優(yōu)點:
高效的 Diff 算法。
簡單且有助于提高性能。
沒有 React 也可以使用
足夠輕量
允許構(gòu)建應(yīng)用程序且不考慮狀態(tài)轉(zhuǎn)換
增量Dom的主要概念是將組件編譯成一系列的指令,這些指令去創(chuàng)建DOM樹并在數(shù)據(jù)更改時就地的更新它們。
例如:
@Component({ selector: 'todos-cmp', template: ` <p *ngFor="let t of todos|async"> {{t.description}} </p> ` }) class TodosComponent { todos: Observable<Todo[]> = this.store.pipe(select('todos')); constructor(private store: Store<AppState>) {} }
編譯后:
var TodosComponent = /** @class */ (function () { function TodosComponent(store) { this.store = store; this.todos = this.store.pipe(select('todos')); } TodosComponent.ngComponentDef = defineComponent({ type: TodosComponent, selectors: [["todos-cmp"]], factory: function TodosComponent_Factory(t) { return new (t || TodosComponent)(directiveInject(Store)); }, consts: 2, vars: 3, template: function TodosComponent_Template(rf, ctx) { if (rf & 1) { // create dom pipe(1, "async"); template(0, TodosComponent_p_Template_0, 2, 1, null, _c0); } if (rf & 2) { // update dom elementProperty(0, "ngForOf", bind(pipeBind1(1, 1, ctx.todos))); } }, encapsulation: 2 }); return TodosComponent; }());
增量DOM的優(yōu)點:
渲染引擎可以被Tree Shakable,降低編譯后的體積
占用較低的內(nèi)存
為什么可渲染引擎可以被 Tree Shakable?
Tree Shaking 是指在編譯目標(biāo)代碼時移除上下文中未引用的代碼,增量 DOM 充分利用了這一點,因為它使用了基于指令的方法。正如示例所示,增量 DOM 在編譯之前將每個組件編譯成一組指令,這有助于識別未使用的指令。在 Tree Shakable 過程中,可以將這些未使用的的指令刪除掉。
減少內(nèi)存的使用
與虛擬 DOM 不同,增量 DOM 在重新呈現(xiàn)應(yīng)用程序 UI 時不會生成真實 DOM 的副本。此外,如果應(yīng)用程序 UI 沒有變化,增量 DOM 就不會分配任何內(nèi)存。大多數(shù)情況下,我們都是在沒有任何重大修改的情況下重新呈現(xiàn)應(yīng)用程序 UI。因此,按照這種方法可以極大的減少設(shè)備內(nèi)存使用。
關(guān)于“Angular中的變化檢測實例分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。
文章題目:Angular中的變化檢測實例分析
網(wǎng)頁URL:http://m.newbst.com/article28/gcspjp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、網(wǎng)站收錄、網(wǎng)頁設(shè)計公司、定制開發(fā)、關(guān)鍵詞優(yōu)化、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)