我所經歷的JS性能優化

折騰了好幾天,糾結了好幾天,鬱悶了好幾天,終於在今天可以釋懷了,留下其中的苦樂辛酸來和大家分享。

   事情是這樣子的,上週接到一個需求,其中涉及到一個好友選擇的組件,就是單機左側某個羣組下的好友後該好友移動到右側,視爲選擇了它,另外每個羣組還有全選,摺疊和展開等功能。組件在開發過程中,遇到了在2000條數據的時候,搜索會變的很卡,IE8下爲2s左右,IE6更長,我在最初的優化過程中我使用事件代理,文檔片段,字符串數組,少創建對象,緩存一切可以緩存的,用hash超找代替數組查找等方式,但是一直沒有找到性能的瓶頸所在,所以效果不大,後來採用了setTimeout的方式,就是限制js的執行時間,當它超過規定的時間後記錄當前的執行狀態,然後setTimeout延遲一段時間再執行,而把延時的這段時間交給UI線程,這樣做後確實不卡了,但是因爲出現延時調用,搜索的總體時間變長了,試想讓用戶等十多秒來看搜索的結果這樣做也太不合理,問題一直沒有得到根本的解決。

       後來,在johnnie和youkun的幫助和提示下,我找到了優化的入口就是找性能瓶頸,就是如果一個段代碼很耗時的話你可以註釋掉一部分你認爲是很耗時的,或者乾脆全部註釋掉,然後再一點一點的解開,按照這個思路,我發現在我的循環搜索中頻繁進行了dom操作,就比如搜索用戶提交的一個queryString,我的方法是在數據中遍歷所有的item,如果匹配,就通過這條數據找到這個item對應的dom,然後顯示它,不匹配就隱藏它,然後每個組搜索完還要更新該組搜索的結果數,這裏面涉及到選擇dom,然後顯示或者隱藏它等,正是這些dom操作在大數據量的時候使得搜索操作變得很慢,當時我試驗了下,就算在循環中只執行一個document.getElementById也很耗時,找到了問題的根源所在,接下來的優化就有了方向,於是在v3版本中我改變了搜索的策略,循環遍歷的時候只拼接dom,在循環結束後一次性的放到文檔中,經過測速,循環遍歷拼接dom只用了不超過60ms,而把這一大段html放到文檔中這一個操作在IE下耗時250ms左右,雖然離大師們推薦的100ms還有差距,但是相對v2的2s提升了很多,我也終於鬆了一口氣了。
     小結:其實js優化一定要掌握方法,沒有正確的方法可能做了很多工作都是偏離主題的,按照正確的優化方法來優化就會定位性能瓶頸,然後對其採取進行有效的 優化措施,而js優化中最主要的還是對dom操作的優化,單純的js執行時間是很短的,而js和dom之間的交互是通過接口來完成,通過接口來完成的都會 有延時,所以要儘量減少dom操作,尤其是在大循環中。
     最後,總結下常見的dom操作的優化方法(節選自高性能JavaScript)

     1  最小化dom訪問次數,儘可能在js端執行;
     2  如果需要多次訪問某個dom節點,請使用局部變量存儲對它的引用;
     3  小心處理html集合,因爲它實時連繫着底層的文檔,把集合的長度緩存到一個變量中,並在迭代中使用它,如果需要經常操作集合,建議把它拷貝到一個數組中;
     4  如果可能的話,使用速度更快的API,比如querySelectorAll和firstElementChild;
     5  要留意重繪和重排;批量修改樣式時,“離線”操作dom樹;使用緩存,並減少訪問佈局的次數;
     6  動畫中使用絕對定位,使用拖放代理
     7  使用事件委託來減少事件處理器的數量

     總結下js中對數據訪問的優化(節選自高性能JavaScript)

     1  函數中讀寫局部變量總是最快的,而全局變量的讀取則是最慢的;
     2  儘可能地少用with 語句,因爲它會增加with 語句以外的數據的訪問代價;
     3  閉包儘管強大,但不可濫用,否則會影響到執行速度以及內存;
     4  嵌套的對象成員會明顯影響性能,儘量少用;
     5  避免多次訪問對象成員或函數中的全局變量,儘量將它們賦值給局部變量以緩存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章