1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        使用 DevTools 對(duì) Angular 前端應(yīng)用性能分析優(yōu)化

        共 2588字,需瀏覽 6分鐘

         ·

        2022-01-10 12:31

        使用 lighthouse 評(píng)分

        以南寧IT派[www.nnitpai.com]為例記錄分析優(yōu)化過(guò)程,使用 Devtools lighthouse 對(duì)首頁(yè)進(jìn)行綜合的評(píng)分:

        7fa079c11369b8646ed7eb61c488302b.webp

        性能評(píng)分勉強(qiáng)及格差強(qiáng)人意,切換到 performance 性能選項(xiàng)卡:

        6ad096b843a6134d43e47cc9a6d05050.webp

        記錄的同時(shí),可以依次滾動(dòng)頁(yè)面到底部,暫??纯捶治鼋Y(jié)果:

        20d23eac4b1fe57779c829bb98958fcb.webp

        發(fā)現(xiàn)一推很深的函數(shù)調(diào)用,放大具體看看:(記得要用本地開發(fā)環(huán)境來(lái)查看,這樣可以方便看未編譯版本中具體的組件或者函數(shù))

        5d6d88d0b4ff5e10cf59b6d4b7a4739f.webp

        發(fā)現(xiàn)大部分的深度調(diào)用都與這個(gè) MenuComponent 組件有關(guān),不斷的在調(diào)用刷新,可以看到一個(gè) executeTemplate 這個(gè)函數(shù),這個(gè)是angular對(duì)模板里面的變量或者函數(shù)執(zhí)行計(jì)算值,已檢測(cè)是否有變化,相應(yīng)進(jìn)行渲染。

        看看 MenuComponent 組件模板關(guān)鍵部分:

        <ng-container?*ngIf="content">
        ??<header?*ngIf="screen.eq('gt-sm')"?class="header"?#header>
        ????//
        ??header>
        ??<div?class="drawer">
        ????<mat-toolbar?*ngIf="screen.eq('lt-md')">
        ??????//
        ????mat-toolbar>
        ????<div?[hidden]="!(screen.eq('lt-md')?&&?isDrawer)">
        ??????//
        ????div>
        ??div>
        ng-container>

        里面有個(gè)方法調(diào)用screen.eq()在eq方法打個(gè)log看看日志:

        4b8a7b3f09bd29a23a01e3550dd3e6dc.webp

        只要頁(yè)面有事件發(fā)生,比如dom的更改,這個(gè)log一直飆升,導(dǎo)致嚴(yán)重的性能問(wèn)題,問(wèn)題應(yīng)該就是在這里,為什么會(huì)被反復(fù)執(zhí)行?

        簡(jiǎn)單了解 Angular 的默認(rèn)更新檢測(cè)機(jī)制

        有幾種情況會(huì)觸發(fā) Angular 檢測(cè):

        • 用戶的輸出操作,點(diǎn)擊、提交、滾動(dòng)等等
        • http 請(qǐng)求
        • 定時(shí)事件,setTimeout\setInterval

        變更檢測(cè)機(jī)制是 Angular 內(nèi)置的框架功能,可確保組件的數(shù)據(jù)與HTML模板視圖進(jìn)行自動(dòng)同步,對(duì)于模板中使用的表達(dá)式,它將當(dāng)前值與先前值進(jìn)行比較,如果值不同則 isChanged,然后進(jìn)行更新,組件的檢測(cè)機(jī)制:

        • Default: 默認(rèn)的檢測(cè)機(jī)制,比較事件發(fā)生前后的模板表達(dá)式值來(lái)決定是否更新視圖,只要有更新,會(huì)更新整個(gè)數(shù)組樹。
        • OnPush: 檢測(cè)組件的Input輸入或者異步管道訂閱的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)更新;

        尋找問(wèn)題的原因

        當(dāng)頁(yè)面滾到在背景視頻的時(shí)候,log的輸出特別的密集,仔細(xì)觀察這個(gè)組件有DOM數(shù)據(jù)的刷新:

        67e806e01acdbb07e2c94fe14ccbb6ab.webp

        這應(yīng)該是使用了定時(shí)器更新了當(dāng)前的播放時(shí)間,導(dǎo)致 angular 不斷觸發(fā)監(jiān)測(cè)機(jī)制。

        解決問(wèn)題

        把組件默認(rèn)監(jiān)測(cè)機(jī)制更改為OnPush

        從而可以忽略外部其他組件的變更周期,當(dāng)輸入屬性發(fā)生變化時(shí)才會(huì)觸發(fā)。

        import?{
        ??Component,
        ??OnInit,
        ??Input,
        ??ChangeDetectionStrategy,
        }?from?'@angular/core';
        @Component({
        ??selector:?'app-menu',
        ??templateUrl:?'./menu.component.html',
        ??styleUrls:?['./menu.component.scss'],
        ??changeDetection:?ChangeDetectionStrategy.OnPush,
        })

        手動(dòng)更新檢查

        screen.eq('xs') 方法是用來(lái)檢測(cè)當(dāng)前屏幕的媒體查詢,根據(jù)屏幕尺寸做出顯示邏輯,使用 OnPush方式時(shí),模板表達(dá)式不會(huì)再隨著外部的檢測(cè)周期影響到,當(dāng)頁(yè)面寬度發(fā)生變化時(shí),我們就需要手動(dòng)的去告訴組件更新檢測(cè)。

        新建一個(gè)媒體查詢的服務(wù),在組件里面訂閱這個(gè)可觀察對(duì)象,這個(gè)觀察對(duì)象會(huì)在瀏覽器寬度發(fā)生變化時(shí)推送當(dāng)前窗口的媒體查詢值:

        mqAlias$():?Observable<string[]>?{
        ????return?this.mediaObserver.asObservable().pipe(
        ??????distinctUntilChanged(
        ????????(x:?MediaChange[],?y:?MediaChange[])?=>
        ??????????this.getAlias(x)?===?this.getAlias(y)
        ??????),
        ??????map((change:?any)?=>?{
        ????????return?change.map((item:?any)?=>?{
        ??????????return?item.mqAlias;
        ????????});
        ??????})
        ????);
        ??}

        并在組件中引用

        @Component({
        ??selector:?'app-menu-item',
        ??templateUrl:?'./menu-item.component.html',
        ??styleUrls:?['./menu-item.component.scss'],
        ??changeDetection:?ChangeDetectionStrategy.OnPush,
        })
        export?class?MenuItemComponent?implements?OnInit?{
        ??@Input()?content:?any;
        ??@Input()?mobileMenu:?any;
        ??showXs:?boolean;
        ??constructor(
        ????private?screen:?ScreenState,
        ????private?screenService:?ScreenService,
        ????private?cd:?ChangeDetectorRef
        ??
        )?{}

        ??ngOnInit():?void?{
        ????if?(this.screenService.isPlatformBrowser())?{
        ??????this.screen.mqAlias$().subscribe((alia)?=>?{
        ????????this.showXs?=?alia.includes('xs');
        ????????this.cd.detectChanges();
        ??????});
        ????}
        ??}
        }

        9006341d4f67ef35ebf9cf3cfedc4ac0.webp

        總結(jié)

        評(píng)分提升還是很明顯的,對(duì)于后面組件的開發(fā)提供了很好的最佳實(shí)踐,多理解熟悉 Angular 的內(nèi)部運(yùn)行機(jī)制,為項(xiàng)目開發(fā)帶來(lái)更好的效益。

        • 要善于使用 lighthouse 進(jìn)行檢測(cè)評(píng)分,針對(duì)不同問(wèn)題具體分析;
        • 多使用 Devtools 分析,查找問(wèn)題的入口;
        • 不要在模板中使用函數(shù)或者getter,當(dāng)有大量變更時(shí),會(huì)存在很多的性能隱患;

        接下來(lái),會(huì)繼續(xù)針對(duì)這個(gè)案例繼續(xù)分析,使項(xiàng)目的 lighthouse 評(píng)分更加友好,提供給各位前端開發(fā)一些借鑒和交流。


        瀏覽 55
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色秘 乱码一区二区三区色欲 | 激情无码影院 | 韩日大奶子姑娘性交 | 亚洲三级一区二区 | 超碰人人操人人爽 | 人摸人人 | 亚洲黄色成人 | 五级黄18以下免费 | 亚洲AV无码成人网站国产网站 | 黄色网址免费在线观看 |