39

我們正在針對我們正在爲銀行開發的Angular應用程序的性能問題猛擊我們的頭腦。Angular JS縮放與性能

不幸的是,顯示代碼片段是違反合同的。無論如何,我可以描述一些正在發生的主要問題,我希望可以推薦最佳做法。

應用結構:

  • 從本質上講,一個巨大的多形式的頁面。
  • 每種形式都是它自己的部分,嵌套的控制器和局部約3層深。
  • 相同的形式在一組json對象上重複。
  • 每個表單都綁定到重複的對象/模型。
  • 我們應該支持頁面上1-200個表單的任何地方。

如果你看看時間表。我們花了很多時間在jQuery parse html方法中,jQuery重新計算stye方法,GC事件(垃圾收集)。我想盡量減少這些應該加快一點。它們都是Angular生命週期的一部分,但可能有更好的方法來避免它們。下面是分析器的一些截圖:

Recalculate Style GC Event

最終,應用程序是作爲呆滯的重複形式的數量變得高於5.每一形式相對無關的其他人。我們試圖不注意表單之間的任何共享屬性。

+2

,問題是。 ..? – Stewie

+0

你有沒有試過追溯這個函數調用到你自己的代碼庫(或角度調用它?)的代碼?@Stewie我相信這個問題(儘管有點編纂)是什麼是可能出現的一般性能瓶頸在AngularJS應用程序中?應該如何處理性能/優化?我相信Chrome的Batarang插件有一些性能(只是檢查,當然確實有一個性能選項卡,雖然我沒有使用它,它可能會有所幫助)。 – shaunhusain

+1

「AngularJS應用程序中可能會出現什麼性能瓶頸?」與任何JavaScript應用程序相同的瓶頸,您創建對象越多,GC的時間就越長。 HTML5rocks網站上有很多關於此的資源。 – mpm

回答

3

通常情況下,如果有超過2000個數據綁定處於活動狀態,那麼AngularJS將表現不佳,即正在髒的範圍內的2000個項目 - 每個$ digest-cycle都會被檢查。由於這個原因,Ng-repeat的性能影響很大;每個重複的項目至少設置兩個綁定,不包括項目內使用的任何附加數據或指令。

一個背後AngularJS開發商給出的髒檢查的細節極好的描述,其在此表現如此回答:

https://stackoverflow.com/a/9693933/179024

這個問題的答案下面的評論線程是值得一讀,我也分享一些關於它的想法在回答中進一步下跌的同一頁上:

https://stackoverflow.com/a/18381836/179024

+0

我認爲米斯科的回答雖然很好,但只部分解決了這個問題。這個問題的一大部分似乎是Angular正在單獨創建每個元素,而不是將它們分配到同一個碎片中。 – DNS

+0

問題可能僅僅在於,通過多個重複表單,每個表單中的每個重複表單都有多個重複的項目,每次運行$ digest時都會監視的項目數量會導致站點變慢。一個很好的方法來檢查這將是Chrome的batarang插件,它將實時顯示摘要時間。但由於OP無法顯示任何代碼,因此查明問題很難。 –

+2

OP確實顯示了事件時間表,大部分顯示的活動都是一系列HTML解析。 Angular可能有這樣一個充分的理由,而不是在一個片段中創建它們,但我認爲這就是爲什麼它在這裏慢;骯髒的檢查似乎不是一個很大的貢獻者。 – DNS

7

很難提供一個解決方案沒有更多的信息關於你的問題,但我最近經歷了(並解決了)a performance issue,可能與你所看到的相似,並且與$消化週期無關。

大多數關於angularjs性能的討論(包括excellent post from Misko)都是關於髒檢查和$ digest循環的性能。但這不是您可以通過angularjs體驗的唯一性能問題。第一步應該是確定摘要循環是否是你的問題。爲此,您可以使用batarang,或者只是查看您的應用程序,以及何時精確緩慢。當摘要週期較慢時,基本上與UI的任何交互都會很慢。您可以擁有快速摘要循環的應用程序,只有在加載,切換視圖或以其他方式更改要顯示的組件集時纔會很慢,並且這可以在分析中體現爲大量時間花費在解析HTML和垃圾收集。在我的情況下,這是通過執行HTML模板來顯示的一些預先計算的,而不是依靠NG重複,NG-開關,NG-如果到處都是解決。

在我正在使用納克重複=「微件在微件」含有關於微件的類型的NG-開關,爲了顯示窗口小部件的任意集合(定製自包含指令)。將其替換爲代碼以生成特定組件的角度模板,加快了從〜10s到幾乎即時的路由切換速度。

你可以看到谷歌組紗線之上多一點信息我如何解決我的具體問題,或者如果你想一些具體的建議提供有關應用程序的更多信息。

+0

您是否仍然使用這種方法獲得2路數據綁定? – Matheus

+0

@matheus:是的,每個小部件的內容仍然有雙向綁定。另一方面,要顯示的小部件列表沒有,它是通過連接每個單獨小部件的模板生成的。 – jssebastian

20

你需要爲了遏制與棱角分明的性能問題來創建自定義指令。與餘燼不同,隨着所有的鐘聲和口哨聲開啓,您可以調整它。以下是我創建的一些幫助你的指令。並非您的應用中的所有數據都需要雙向數據綁定,因此您可以通過在需要的頁面中放置監視表達式來節省寶貴的CPU功耗。所有這些指令都將數據綁定一次,並保持獨立。

https://gist.github.com/btm1/6802599

https://gist.github.com/btm1/6802312

https://gist.github.com/btm1/6746150

一個以上大約有巨大的性能NG-重複談判的答案打,所以我給你「設置重複」一次性數據綁定重複指令: )

2

很抱歉,對於把它作爲一個「答案」,因爲我沒有足夠的積分尚未作出評論。

我們遇到了與我們的AngularJS應用類似的問題。使用'batarang'似乎不得不處理大量的範圍對象,並且它們相關的$ watch表達式會導致性能呃逆。這讓我們想知道是否應該使用另一個框架或類似ReactJS來處理「視圖」部分。

1

將DOM操作轉換爲自定義指令和許多$ watch的$ watch問題之間的中間地帶是使用「綁定一次」語義。

這對於一旦數據可用後不可變的數據很有用。見bindonce

2

儘量避免以下

  1. 請避免使用NG-重複,如果你有 超過50個元素列表的時間和避免人工手錶
  2. 不使用NG-點擊,ng-mouseenter,ng-mouseleave等鼠標事件,直到它是一個迫切的需求,嘗試通過使用$事件對象以及js的事件傳播概念來減少它們的數量

  3. 哪裏有可能使用範圍$ digest instea d範圍。$ watch,這可以確保僅在子範圍內執行摘要循環

    1. 嘗試嵌套作用域,即一個或兩個控制器位於一個父控制器內並將可重用邏輯保留在父對象中,i在使用Ui路由器時使用這種嵌套狀態(以滿足需要更改URL而無需刷新頁面的請求)。

    最重要!從HTML中刪除所有過濾器!

上述所有觸發您的應用程序的所有範圍摘要週期等方面有很高的概率,即使當視圖已經被渲染的角度再次執行無情消化循環

+2

你會用什麼來代替ng-click和ng-repeat? –

+0

使用事件捕獲和冒泡的javascript概念來減少ng-click和ng-repeat使用單個綁定屬性(更新版本的角度js) –

+0

我不會違背穀物,除非你遇到性能問題或者知道你會。防爆。如果你沒有使用事件的內置指令,如果你想更新你的模型,你會被觸發。$ digest()(觸發從當前範圍向下的髒檢查)或更糟糕的$ apply()()這會從$ rootScope中觸發),這比使用ng-click或其他方法(其只爲該範圍註冊另一個觀察者)效率低。 – TaylorMac

0

這不僅會成爲一個鏈接!這只是我閱讀本書時的一個想法,我還沒有探討過這個,但有人可能這樣做,我正在等待他們對我的想法的答覆。如何使用共享網絡工作者從UI線程中獲取大量繁重的處理? https://github.com/h2non/sharedworkers-angular-poc

我的另一個想法是一個更簡單的。您的應用會受益於無限滾動嗎?我的意思是這些表格可能不適合在屏幕上,他們沒有連接到彼此,所以爲什麼不畫他們,因爲他們需要?將它們加載到內存中,然後相應地繪製它們。

0

就像其他任何性能優化一樣,知道如何配置應用程序以查找真正的瓶頸非常重要。然後你可以逐個解決它們。我平時打的瓶頸以下順序:

  • 我的javascript代碼
  • 角度表達式(複雜的觀察家和過濾器),其在每個空閒消化週期運行
  • 角結構(NG-重複,複製的對象Digest循環)

我已經描繪了一個角度示例,逐步顯示如何識別每一步的瓶頸。 http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html

3

爲了提高生產性能閱讀非常漂亮下面的一行:

報價AngularJS文檔:

默認情況下AngularJS附加信息有關綁定和範圍,以DOM節點,並添加CSS類數據綁定元素:

作爲ngBind,ngBindHtml或{{...}}插值的結果,綁定數據和CSS類ng-binding被附加到相應的元素。

如果編譯器創建了一個新的範圍,範圍和ng-scope或ng-isolated-scope CSS類都附加到相應的元素。這些範圍引用可以通過element.scope()和element.isolateScope()來訪問。

工具,比如量角器和Batarang需要這些信息來運行,但你可以在生產中使用禁用此一顯著的性能提升:

myApp.config(['$compileProvider', function ($compileProvider) { 
    $compileProvider.debugInfoEnabled(false); 
}]); 

你可以閱讀更多細節here