久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      淺析Angular變更檢測(cè)中的DOM更新機(jī)制

      淺析Angular變更檢測(cè)中的DOM更新機(jī)制

      前端(vue)入門(mén)到精通課程,老師在線輔導(dǎo):聯(lián)系老師
      Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調(diào)試工具:點(diǎn)擊使用

      變更檢測(cè)是Angular中很重要的一部分,也就是模型和視圖之間保持同步。在日常開(kāi)發(fā)過(guò)程中,我們無(wú)需了解變更檢測(cè),因?yàn)锳ngular都幫我們完成了這一部分工作,讓開(kāi)發(fā)人員更加專(zhuān)注于業(yè)務(wù)實(shí)現(xiàn),提高開(kāi)發(fā)效率和開(kāi)發(fā)體驗(yàn)。但是如果想要深入使用框架,或者想要寫(xiě)出高性能的代碼而不僅僅只是實(shí)現(xiàn)了功能,就必須要去了解變更檢測(cè),它可以幫助我們更好的理解框架,調(diào)試錯(cuò)誤,提高性能等?!鞠嚓P(guān)教程推薦:《angular教程》】

      Angular的DOM更新機(jī)制

      我們先來(lái)看一個(gè)小例子。

      淺析Angular變更檢測(cè)中的DOM更新機(jī)制

      當(dāng)我們點(diǎn)擊按鈕的時(shí)候,改變了name屬性,同時(shí)DOM自動(dòng)被更新成新的name值。

      那現(xiàn)在有一個(gè)問(wèn)題,如果我改變name的值后,緊接著把DOM中的innerText輸出出來(lái),它會(huì)是什么值呢?

      import { Component, ViewChild, ElementRef } from '@angular/core';  @Component({   selector: 'my-app',   templateUrl: './app.component.html',   styleUrls: [ './app.component.css' ] }) export class AppComponent  {   name = 'Empty';    @ViewChild('textContainer') textContainer: ElementRef;    normalClick(): void {     this.name = 'Hello Angular';      console.log(this.textContainer.nativeElement.innerText);   } }
      登錄后復(fù)制

      你答對(duì)了嗎?

      那這兩段代碼中到底發(fā)生了什么呢?

      如果我們用原生JS來(lái)編寫(xiě)這段代碼,那么點(diǎn)擊按鈕后的視圖肯定不會(huì)發(fā)生任何變化,而在Angular中卻讓視圖發(fā)生了變化,那它為什么會(huì)自動(dòng)把視圖更新了呢?這離不開(kāi)一個(gè)叫做zone.js的庫(kù),簡(jiǎn)單來(lái)說(shuō),它是對(duì)發(fā)生值改變的事件做了一些處理,這個(gè)會(huì)在后面的部分詳細(xì)講解,這里暫時(shí)知道這個(gè)就可以了。

      如果我不想讓這個(gè)庫(kù)做這些處理,Angular還為我們提供了禁用zone.js的方法。

      可以在main.ts中設(shè)置禁用zone.js。

      import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';  import { AppModule } from './app/app.module'; import { environment } from './environments/environment';  if (environment.production) {   enableProdMode(); }  platformBrowserDynamic().bootstrapModule(AppModule, {   ngZone: 'noop' })   .catch(err => console.error(err));
      登錄后復(fù)制

      淺析Angular變更檢測(cè)中的DOM更新機(jī)制

      當(dāng)我們禁用zone.js,視圖并未發(fā)生更新。到源碼里找一下視圖更新的相關(guān)代碼。

       */ class ApplicationRef {     /** @internal */     constructor(_zone, _injector, _exceptionHandler, _initStatus) {         this._zone = _zone;         this._injector = _injector;         this._exceptionHandler = _exceptionHandler;         this._initStatus = _initStatus;         /** @internal */         this._bootstrapListeners = [];         this._views = [];         this._runningTick = false;         this._stable = true;         this._destroyed = false;         this._destroyListeners = [];         /**          * Get a list of component types registered to this application.          * This list is populated even before the component is created.          */         this.componentTypes = [];         /**          * Get a list of components registered to this application.          */         this.components = [];         this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({             next: () => {                 this._zone.run(() => {                     this.tick();                 });             }         });         ...     }  /**      * Invoke this method to explicitly process change detection and its side-effects.      *      * In development mode, `tick()` also performs a second change detection cycle to ensure that no      * further changes are detected. If additional changes are picked up during this second cycle,      * bindings in the app have side-effects that cannot be resolved in a single change detection      * pass.      * In this case, Angular throws an error, since an Angular application can only have one change      * detection pass during which all change detection must complete.      */     tick() {         NG_DEV_MODE && this.warnIfDestroyed();         if (this._runningTick) {             const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?                 'ApplicationRef.tick is called recursively' :                 '';             throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, errorMessage);         }         try {             this._runningTick = true;             for (let view of this._views) {                 view.detectChanges();             }             if (typeof ngDevMode === 'undefined' || ngDevMode) {                 for (let view of this._views) {                     view.checkNoChanges();                 }             }         }         catch (e) {             // Attention: Don't rethrow as it could cancel subscriptions to Observables!             this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));         }         finally {             this._runningTick = false;         }     }  }
      登錄后復(fù)制

      大致解讀一下,這個(gè)ApplicationRef是Angular整個(gè)應(yīng)用的實(shí)例,在構(gòu)造函數(shù)中,zone(zone庫(kù))的onMicrotaskEmpty(從名字上看是一個(gè)清空微任務(wù)的一個(gè)subject)訂閱了一下。在訂閱里,調(diào)用了tick(),那tick里做了什么呢?

      思考: 上次說(shuō)了最好訂閱不要放到constructor里去訂閱,這里怎么這么不規(guī)范呢?

      當(dāng)然不是,上次我們說(shuō)的是Angular組件里哪些應(yīng)該放constructor,哪些應(yīng)該放ngOnInit里的情況。但這里,ApplicationRef人家是一個(gè)service呀,只能將初始化的代碼放constructor。

      在tick函數(shù)里,如果發(fā)現(xiàn)這個(gè)tick函數(shù)正在執(zhí)行,則會(huì)拋出異常,因?yàn)檫@個(gè)是整個(gè)應(yīng)用的實(shí)例,不能遞歸調(diào)用。然后,遍歷了所有個(gè)views,然后每個(gè)view都執(zhí)行了detectChanges(),也就是執(zhí)行了下變更檢測(cè),什么是變更檢測(cè),會(huì)在后面詳細(xì)講解。緊接著,如果是devMode,再次遍歷所有的views,每個(gè)view執(zhí)行了checkNoChanges(),檢查一下有沒(méi)有變化,有變化則會(huì)拋錯(cuò)(后面會(huì)詳細(xì)說(shuō)這個(gè)問(wèn)題,暫時(shí)跳過(guò))。

      那好了,現(xiàn)在也知道怎么能讓它更新了,就是要調(diào)用一下ApplicationReftick方法。

      import { Component, ViewChild, ElementRef, ApplicationRef } from '@angular/core'; @Component({   selector: 'app-root',   templateUrl: './app.component.html',   styleUrls: ['./app.component.scss'] }) export class AppComponent  {   name = 'Empty';    @ViewChild('textContainer') textContainer: ElementRef = {} as any;    constructor(private app: ApplicationRef){}    normalClick(): void {     this.name = 'Hello Angular';      console.log(this.textContainer.nativeElement.innerText);      this.app.tick();   } }
      登錄后復(fù)制

      果然,可以正常的更新視圖了。

      我們來(lái)簡(jiǎn)單梳理一下,DOM的更新依賴(lài)于tick() 的觸發(fā),zone.js幫助開(kāi)發(fā)者無(wú)需手動(dòng)觸發(fā)這個(gè)操作。好了,現(xiàn)在可以把zone.js啟用了。

      那什么是變更檢測(cè)呢?繼續(xù)期待下一篇哦。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)