溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

angular怎么進行性能優(yōu)化

發(fā)布時間:2022-09-20 15:08:00 來源:億速云 閱讀:335 作者:iii 欄目:web開發(fā)

這篇“angular怎么進行性能優(yōu)化”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“angular怎么進行性能優(yōu)化”文章吧。

angular 性能優(yōu)化——變更檢測

什么是頁面流暢度?

頁面流暢度是通過幀率 FPS(Frames Per Second - 每秒傳輸幀數(shù))判定的,一般主流的瀏覽器屏幕刷新率都在 60Hz(每秒刷新60次),最優(yōu)的幀率在 60 FPS,幀率越高,頁面就越流暢,60Hz意味著每隔16.6ms會刷新一次顯示屏,也就是每一次渲染頁面需要在16.6ms內(nèi)完成,否則就會導致頁面失幀,出現(xiàn)卡頓現(xiàn)象。根因在于:瀏覽器中的 JavaScript 執(zhí)行和頁面渲染會相互阻塞。

在 Chrome 的 devtools 中我們可以執(zhí)行 Cmd+Shift+P 輸入 show fps 來快速打開 fps 面板,如下圖所示:

angular怎么進行性能優(yōu)化

通過觀察 FPS 面板,我們可以很方便的對當前頁面的流暢度進行監(jiān)控

angular怎么進行性能優(yōu)化

1 影響頁面性能的因素

頁面交互是否流暢,在于頁面響應是否流暢,而頁面響應其本質(zhì)上就是把頁面狀態(tài)的變更重新渲染到頁面上的過程。

頁面響應過程大致如下:

angular怎么進行性能優(yōu)化

一般情況Event Handler事件處理邏輯不會消耗太多時間,所以影響angular性能的因素主要在于異步事件觸發(fā)變更檢測。 一般情況Event Handler事件處理邏輯不會消耗太多時間,所以影響angular性能的因素主要在于異步事件觸發(fā)和變更檢測。

對angular來說,頁面渲染的過程就是變更檢測的過程,可以理解為angular的變更檢測要在16.6ms內(nèi)完成才不會導致頁面失幀、卡頓。

可以從以下三方面優(yōu)化頁面響應的性能。

(1)對于觸發(fā)事件階段,可以減少異步事件的觸發(fā),來減少整體的變更檢測次數(shù)和重新渲染;

(2)對于 Event Handler 執(zhí)行邏輯階段,可以通過優(yōu)化復雜代碼邏輯來減少執(zhí)行時間;

(3)對于 Change Detection 檢測數(shù)據(jù)綁定并更新 DOM 階段,可以減少變更檢測模板數(shù)據(jù)的計算次數(shù)來減少渲染時間;

對于(2)Event Handler要具體問題具體分析,不做討論,主要針對(1)(3)進行優(yōu)化

2 優(yōu)化方案

2.1 減少異步事件觸發(fā)

Angular在默認變更檢測模式下,異步事件會觸發(fā)全局的變更檢測,因此,減少異步事件的觸發(fā)會大大的提升angular的性能。

異步事件包括Macro Task(宏任務)事件和Micro Task微任務事件

對異步事件的優(yōu)化主要是針對document的監(jiān)聽事件。比如document上的click、mouseup、mousemove…等監(jiān)聽事件。

監(jiān)聽事件場景:

Renderer2.listen(document, …)

fromEvent(document,…)

document.addEventListener(…)

dom監(jiān)聽事件,在不需要觸發(fā)的時候一定要移除。

舉例:[pop]提示框指令

使用場景:表格列篩選,點擊圖標以外的地方,或者頁面滾動,列篩選彈框隱藏

以前的做法是直接在pop指令里監(jiān)聽document的click事件和scroll事件,這樣有個弊端就是提示框未顯示,但依然存在監(jiān)聽事件,很不合理。

合理的解決方案:當提示框顯示的時候才去監(jiān)聽click和scroll事件,隱藏的時候就移除監(jiān)聽事件。

angular怎么進行性能優(yōu)化

對于頻繁觸發(fā)的dom監(jiān)聽事件,可以使用rjx的操作符對事件進行優(yōu)化。詳情參考Rjx操作符。RxJS Marbles。

2.2 變更檢測

什么是變更檢測?

要理解變更檢測,我們可以從變更檢測的目標尋找答案。angular變更檢測目標,是讓模型(TypeScript代碼)與模板(HTML)保持同步。因此,變更檢測可以理解為:檢測模型變更的同時,更新模板( DOM 。

變更檢測流程是什么?

angular怎么進行性能優(yōu)化

通過在組件樹中按照自頂向下的順序執(zhí)行變更檢測,也就是先對父組件執(zhí)行變更檢測,再對子組件進行變更檢測。首先檢查父組件的數(shù)據(jù)變更,然后更新父組件模板,在更新模板的時候遇到子組件,會去更新子組件上綁定的值,然后進入子組件,看@Input輸入值的索引是否改變,如果改變就將該子組件標記為dirty,也就是后續(xù)需要變更檢測的,標記完子組件之后,繼續(xù)更新父組件中子組件后面的模板,父組件模板全部更新完之后再去對子組件做變更檢測。

2.2.1 angular變更檢測原理

在默認變更檢測default模式下,異步事件觸發(fā)Angular的變更檢測的原理是 angular通過使用Zone.js處理異步事件時調(diào)用了ApplicationRef 的tick()方法從根組件到子組件執(zhí)行變更檢測。 Angular 應用初始化過程中,實例化了一個zone (NgZone),然后將所有邏輯都跑在該對象的 _inner 對象中。

Zone.js實現(xiàn)了以下幾個類:

  • Zone類,JavaScript 事件的執(zhí)行環(huán)境,和線程一樣,它們可以帶一些數(shù)據(jù),并且可能擁有父子 zone。

  • ZoneTask類,包裝后的異步事件,這些 task 有三種子類:


    • MicroTask,由 Promise 創(chuàng)建。

    • MacroTask,由 setTimeout 等創(chuàng)建。

    • EventTask,由 addEventListener 等創(chuàng)建,比如dom事件。

  • ZoneSpec對象,創(chuàng)建一個 ngZone 時給它提供的參數(shù),有三個可以觸發(fā)檢測的鉤子:


    • onInvoke,調(diào)用某個回調(diào)函數(shù)時觸發(fā)的鉤子。

    • onInvokeTask,ZoneTask 被觸發(fā)時觸發(fā)的鉤子,比如 setTimeout 到時。

    • onHasTask,檢測到有或無 ZoneTask 時觸發(fā)的鉤子(即對第一個 schedule 的 zone 和最后一個 invoke 或 cancel 的 task 觸發(fā))。

  • ZoneDelegate類,負責調(diào)用鉤子。

檢測過程原理大概如下:

用戶操作觸發(fā)異步事件(比如:dom事件,接口請求…)

=>  ZoneTask類處理事件。invokeTask()函數(shù)中調(diào)用zone的runTask()方法,在runTask方法中,zone通過_zoneDelegate實例屬性,調(diào)用ZoneSpec的鉤子

=>  ZoneSpec的三個鉤子(onInvokeTask、onInvoke、onHasTask)鉤子里通過checkStable()函數(shù)觸發(fā)zone.onMicrotaskEmpty.emit(null)通知

=>  根組件監(jiān)聽onMicrotaskEmpty后調(diào)用tick(),tick方法中調(diào)用 detectChanges()從根組件開始檢測

=> ··· refreshView()調(diào)用executeTemplate(),executeTemplate方法中調(diào)用templateFn()更新模板、子組件綁定的值(這時候會去檢測子組件的@Input()輸入引用是否改變,如果有改變,會將子組件標記為Dirty,也就是該子組件需要變更檢測

詳細變更檢測原理流程圖:

angular怎么進行性能優(yōu)化

簡化流程:

觸發(fā)異步事件

=>  ZoneTask處理事件

=> ZoneDelegate 調(diào)用ZoneSpec的鉤子觸發(fā)onMicrotaskEmpty通知

=> 根組件收到onMicrotaskEmpty通知,執(zhí)行tick(),開始檢測并更新dom

angular怎么進行性能優(yōu)化

由以上代碼可知,當微任務為空的時候才會觸發(fā)變更檢測。

簡略變更檢測原理流程圖:

angular怎么進行性能優(yōu)化

2.2.2 變更檢測優(yōu)化方案

1 )使用OnPush 模式

原理:減少1次變更檢測的耗時。

OnPush模式與Default模式的區(qū)別在于:dom監(jiān)聽事件、timer事件、promise都不會觸發(fā)變更檢測。Default模式的組件狀態(tài)始終為CheckAlways,表示組件每次檢測周期都要檢測。

OnPush模式下:以下情況會觸發(fā)變更檢測

S1、組件的@Input引用發(fā)生變化。

S2、組件的DOM綁定的事件,包括它子組件的DOM綁定的事件,比如 click、submit、mouse down。@HostListener()

注意:

通過renderer2.listen()監(jiān)聽的dom事件不會觸發(fā)變更檢測

通過dom.addEventListener()原生監(jiān)聽方式也不會觸發(fā)變更檢測

S3、Observable 訂閱事件,同時設(shè)置 Async pipe。

S4、利用以下方式手動觸發(fā)變化檢測:

ChangeDetectorRef.detectChanges():觸發(fā)當前組件和非OnPush子組件的變更檢測。

ChangeDetectorRef.markForCheck():將當前視圖及其所有的祖先標記為臟,下次檢測周期時候會觸發(fā)檢測。

ApplicationRef.tick():不會觸發(fā)變更檢測

2 )使用NgZone.runOutsideAngular()

原理:減少變更檢測次數(shù)

將全局dom事件監(jiān)聽寫在NgZone.runOutsideAngular()方法的回調(diào)里面,dom事件將不會觸發(fā)angular的變更檢測。如果當前組件未更新,可以在回調(diào)函數(shù)里執(zhí)行ChangeDetectorRef的detectChanges()鉤子來手動觸發(fā)當前組件的變更檢測。

舉例:app-icon-react動態(tài)圖標組件

angular怎么進行性能優(yōu)化

2.2.3 調(diào)試方式

方式1:可以在瀏覽器控制臺,使用Angular DevTools插件查看某一次dom事件,angular的檢測情況:

angular怎么進行性能優(yōu)化

方式2:可以在控制臺直接輸入:ng.profiler.timeChangeDetection()查看檢測時間,這種方式可查看全局的檢測時間。參考博客 Profiling Angular Change Detection

angular怎么進行性能優(yōu)化

2.3 模板(HTML)優(yōu)化

2.3.1 減少DOM渲染:ngFor加trackBy

使用 *ngFor 的 trackBy 屬性,Angular 只更改和重新渲染已更改的條目,而不必重新加載整個條目列表。

比如:表格排序場景。ngFor如果加了trackBy,表格渲染的時候只會移動行dom元素,如果不加trackBy,會先刪除現(xiàn)有的表格dom元素,再新增行dom元素。顯然只移動dom元素性能會好很多。

2.3.2 模板表達式中不要使用函數(shù)

不要在Angular 模板表達式中使用函數(shù)調(diào)用,可以用管道pipe代替,也可以通過手動計算后用一個變量代替。模板中使用函數(shù),不管值有沒有改變,每次變更檢測的時候都會執(zhí)行函數(shù),會影響性能。

模板中使用函數(shù)的場景:

angular怎么進行性能優(yōu)化

2.3.3 減少ngFor的使用

使用ngFor,數(shù)據(jù)量大的時候會影響性能。

舉例:

使用ngFor:

angular怎么進行性能優(yōu)化

angular怎么進行性能優(yōu)化

不使用ngFor:性能提升10倍左右

angular怎么進行性能優(yōu)化

angular怎么進行性能優(yōu)化

以上就是關(guān)于“angular怎么進行性能優(yōu)化”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI