最近一段時間一直在處理公司的一個內部項目哈,因為頁面卡的問題被吐槽了一個月了。因為是接手別人的項目,雖然說不是自己直接造成的。但是解決這個問題已是迫在眉睫了。
可能我們在做前端開發的時候,很少去關注內存的問題,這是因為JS有自己垃圾回收機制,如果代碼不是濫用閉包,一般來說,不會出現性能問題。
![記錄基於vue在我的真實項目中的性能優化](http://p2.ttnews.xyz/loading.gif)
先來大概說下我的項目中性能瓶頸的現象:項目是一個基於electron+vue的一個類似微信桌面端的項目,因為是公司項目就不截圖了,想象是微信就行了。
當我們切換左側聯繫人列表的時候,發現內存不斷的上升,而且很難降下來,很典型的內存洩露了。
時間一長,內存吃完了,程序直接崩了。。。
好吧,解決問題吧,知道有內存洩露,我們一般會找項目中的代碼是不是有沒有及時釋放的閉包局部變量。
但是,效果不明顯。
我的解決方案
1、查看當前頁面的dom節點數。
一般來說在3000左右是為正常吧。這個如果查看呢?
很簡單,我們只需要在瀏覽器控制檯輸入:
$$("*")
即可!
![記錄基於vue在我的真實項目中的性能優化](http://p2.ttnews.xyz/loading.gif)
當我在我的項目中輸入的時候,節點達到了10000+了,好傢伙,問題找到了,原來是dom渲染太多了?
這應該是一個瓶頸吧,接下來不是去掉多餘的dom了,我發現在渲染列表的時候,一些很多的原點是沒有必要時時渲染的,還有一些dom是通過v-show來隱藏起來的。
慢慢的把這些問題解決了,dom節點降下來了。內存是得到了很好的控制。
你們以為這就完了嗎?
但是隨著列表的切換,內存還是會上升,只是沒那麼明顯了。
What??
你們說氣人不?沒辦法,還得繼續優化了。
這時候,我們要結合我的第一種方案,形成第二種方案。
2、優化渲染列表本身。
一般來說,我們列表的數據是通過後端或者本地數據庫獲取到的一個數組對象,而數組的每一項一般都是一個Json對象。我們是直接將這個數據對象掛載到組件的data對象或者vuex中去。
不管是哪種方案,在讀過vue源碼後,知道他是存在一問題的。
首先,我們的組件的data對象下數據,vue為了雙向數據綁定,會給每一個屬性添加get和set函數。也就是說。一個數據對象所有的屬性都會添加一次get和set,但是如果說我們的列表中的數據不需要數據響應,那這個get和set是沒有意義的。
好了,有這個思路,我們應該要想辦法不讓vue去給這個列表數據添加get和set。那該怎麼做呢?
要麼說閱讀源碼很重要呢?因為我之前看過數據響應的相關源碼哈,我就直接帶大家看一眼吧。
在defineReactive方法中,它是專門用來定義get和set的,我們可以看到有一個情況他是不進行get和set的,當對象的configable為false的時候。
一般來說,一個對象的configurable屬性為false的時候。
好像看到希望了
在ES5中,Object對象下有一個方法可以!!!
Object.freeze ,它可以將一個對象凍結起來。
當我們用Object.freeze將對象凍結的時候,我們再來看效果
結果一目瞭然了吧。
好了,接下來我們將我們要渲染的列表用Object.freeze來凍結。再來看效果。
果不其然,內存下來了,正常了。。。哈哈哈
問題來了,當我們把對象凍結後,如果我們想去修改數組中的某一項的數據的時候,這時候我們是無法直接修改的。這時候,我們需要先將凍結後的數組拿到,然後通過[...list];進行解凍。然後修改,然後將新的數組重新凍結再去更新data或者 vuex! 完美解決。
技術總結:
在排查問題的同時,我先考慮了本地數據庫的性能問題,排除後再去排查ui的問題。
我們在vue項目開發的時候,一定要注意我們看不到的頁面不要渲染無效的dom結構,要想提高列表的渲染性能,Object.freeze能大大幫助們提高頁面性能。
從排查問題,到解決問題,過程是痛苦的,但是當問題被解決的時候,被用戶肯定的時候,這些都值了。。
如果大家還有其它更好的優化方案,評論區告訴我下啊。
這裡是暢哥聊技術,歡迎關注,堅持將自己的一線開發經驗形成技術文章,希望能幫助到大家。
全文完!
閱讀更多 暢哥聊技術 的文章