angularJs项目实战!04:angularjs的性能问题
上一篇文章中我花了很多口舌去介紹angularjs是一個中型框架,面對大型應用時少不了第三方類庫的配合。而我的核心議題是:如何以angularjs的思路使用其他類庫,這里jquery是最好的例子了,誰讓它爭議最大。許多人一看到jquery就火冒三丈沖過來覺得這貨是影響代碼結構、打破angular way的純潔的罪魁禍首,但事實是好的木匠總是會允許爛木頭的存在,何況jquery并非爛木頭。只要配合得當jquery完全可以做你項目中的小伙伴,而如果不改變傳統的思路,就算用了angularjs你的代碼也不容易維護。
不過對于angularjs本身來說,以上這個問題純粹是使用者的理念和設計方法的問題,并不重要。重要的問題是,angularjs是個中型框架,做一個大型應用,往大了講功能略顯不足(比如缺少好用的UI插件和異步模塊載入機制),往小了說又不夠靈活(例如不能無縫與第三方路由整合)。但這些都不是最要命的。功能不足用第三方類庫補嘛,不夠靈活就學會適應吧,但最要命的問題是,性能效率問題。
怎么個性能效率問題呢?你可以自己測試一下:在一個頁面上搞500+個不同的ng-model,然后看看頁面的渲染效率會低到什么程度就知道了。
有人會說,誰沒事干在一個頁面上搞那么多ng-model啊!這肯定是寫頁面的人模塊沒有劃分好!但事實是,這種情況很容易出現,例如,在顯示一個angularjs實現的長列表的時候。
我大半年前曾經歡喜于angularjs的特性,而苦于沒有一個好的基于angularjs的grid(表格)插件,于是自己動手瞎寫了一個,叫anGrid. 代碼已經很久沒有維護了。但是還能用。 各位大爺輕噴。https://github.com/zhangdiwaa/anGrid
這個程序一開始運行無誤,在顯示20行X11列的列表(約造成了250個ng-model)毫無問題,反應也很快。配合angularjs的過濾器,排序、替換圖標什么的就是手到擒來啊!
但問題很快發生了,我用了一個測試數據,造成了大約250行X11列的大列表(約造成了2900個ng-model),結果這個列表在chrome瀏覽器下居然渲染了20秒才出來,我還以為電腦死機了。測試了很多次都是如此。我認為是自己代碼寫的太爛。直到我做了1000+的ng-model測試,和看了同學侯振宇的博客以及angularjs源碼才覺悟過來,其實angularjs也不是十全十美的。
Talk is cheap,我們直接來看內部實現吧。
angularjs雙向綁定的核心是$digest方法。這個函數會直接檢測“所有的數據模型”是否改動,有改動就去更新相應的視圖元素。但事實上,看了源碼我們就會發現這個$digest方法執行效率不會高。3重大循環嚇死人,還要監聽同步。連大神自己都在代碼注釋里吐槽說:yes,this code is a bit crazy.
$digest方法,請注意注釋部分,中間有刪截(感謝侯振宇的截圖)
對于這個性能問題,只有換個框架才能改變。
我的同學侯振宇他們所在的團隊,為此專門搞了個全新的MVVM框架avalon,性能超過angularjs 10倍——ng-model超過1萬都很快。原理是將數據模型中的屬性用get 和set 方法重寫。在set方法中去更新所有和當前數據模型有關的視圖元素,這就是為什么avalon一更新數據就能馬上反映到視圖上、并且性能更出眾的原因。直接翻到avalon源碼的“modelFactory”函數,在這個函數中avalon收集和當前模型有關的視圖元素、其他相關聯的數據,最后注冊到屬性中。其中更詳細的原理可以直接參考作者 司徒正美 的github https://github.com/RubyLouvre/avalon
那如果不想換掉angularjs怎么辦?那就努力把每頁的ng-model控制在500以下吧。就上面那個angularjs實現gird表格插件的問題,其實用點“hack”方法也能搞定。假設要顯示250行X11列的gird表格,那么就顯示20行的元素和滾動條,讓其他的元素不渲染不顯示。只有當滾動條向下滑的時候才渲染新的元素,同時消除舊的元素。更進一步的還可以檢測滾動條滾動的速度,滾動得慢就一行一行得預渲染,滾動得快就在停下的時候預渲染。如此就能始終把ng-model的數量控制在一個可以接受的范圍內了。(嘛,這不就跟angular ui 里的ng-grid一樣了嗎!)
來源:?http://community.angular.cn/A0gy
來自為知筆記(Wiz)
總結
以上是生活随笔為你收集整理的angularJs项目实战!04:angularjs的性能问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: salt-ssh 安装salt-mini
- 下一篇: vs实现python c扩展模块