寫出高性能javascript(1)----三個習慣


  做了這么久的前端工程師,總被朋友問到怎么寫出高性能的javascript,那么我今天就來簡單總結下,其實js本身是沒有什么性能問題的,所謂的內存泄露,也主要針對於IE6,IE7,而IE7的內存泄露問題也並不嚴重,這里不討論瀏覽器造成的內存泄露問題,我們只討論,養成什么樣的書寫習慣能夠寫出,高效率高性能的js。

     在這里我總結了三個書寫js的習慣,然后分別針對執行效率,內存問題,安全等各個方面綜合分析要養成這三個習慣的原因。

    1.盡量使用局部變量:

  局部變量的創建和訪問都是特別廉價快捷的,而使用全局變量的話,js對全局變量的調用實際上是對GLOBAL對象的查找引用,性能低下。 而局部變量則是直接創建於當前作用域,不需要有查找引用的過程。不單單是當前作用域,包括閉包里的局部變量訪問,都是很快的。不過,這個過程帶來的優化是需要龐大的js程序長時間的運行才能體現出的。

下面通過細化js解析過程來理解下:

     一個變量具體是局部變量還是全局變量,局部變量的話是在哪層閉包里,是第幾個變量,在編譯的時候就已經確定了,重復的var聲明並不會影響js的執行效率,js執行時,如果是局部變量則會直接在向內存地址里取用,而全局變量則是對象訪問,顯然局部變量在效率上要優化的多。

  但是,不是任何時候局部變量都是最優化的。

  例如,當一個變量是一個表達式或者一個查找dom節點的過程等時,變量的取用中就帶有了查找和計算過程,這樣如果計算次數比較多,用全局變量則可以一次性的固化結果,而使用局部變量反而需要多次計算查找,而影響了效率了。

  總結:

  當然,以上的數據僅僅只對js代碼的執行效率而言,在具體應用中,我仍然推薦大家盡量使用局部變量。因為,js的一個重要的編程理念就是不要污染全局對象,全局對象可能被不同的模塊(甚至頁面上的廣告)訪問,在上面存放數據、函數會有不可預期的后果。所以,我們要靈活使用全局對象和局部變量。

   2.及時釋放回調函數,解除事件綁定。

  上面一個習慣,主要針對於執行效率問題,而這個習慣則是針對內存泄露的問題了。除了古老瀏覽器本身的bug造成的內存泄露外,錯誤的書寫js代碼也會引起內存泄露的問題。

  首先,有如下代碼解釋下這句話的意思:

1 img.onload = function () {
2     img.onload = img.onerror = null;
3 }
4 $(...).on('keyup', function(e){
5     $().off(e);
6 })

  那這么做有什么好處呢,那么我們看下下面的情況:

   比如一個div的keyup和click事件。如果keyup事件引用了div,div又引用着click,那么keyup就會引用click,如果click引用另一個div的keyup,就會導致內存泄露,解綁keyup或者click任何一者都會消除內存泄露。
  而如果不及時釋放回調函數,亦有可能發生以上的問題。
  上面那段話是不是邏輯很復雜呢^ ^,總之養成這個習慣是不會錯的,那就是 及時釋放回調函數,解除事件綁定。

 3.及時清除引用。

     這個習慣也是針對於內存泄露問題,我們先看看以下代碼:

 1 <!doctype html>
 2 <html>
 3 <head>
 4     <title>Memory leak demo</title>
 5 </head>
 6 <body>
 7     <a href="javascript:;">Click me</a>
 8 </body>
 9 <script src="jquery-1.8.0.js"></script><script>
10     $('a').click(function callback(e) {
11         $(this).remove();
12         $('<a href="javascript:;">Click me</a>').appendTo(document.body).click(function(e2){
13             e2.leak = e;
14             callback.call(this, e2);
15         });
16         
17         var current = e, n = 0;
18         while(current.leak){
19             current = current.leak;
20             n++;
21         }
22         console.log('leaked: ' + n);
23         //e = null;
24     });
25 </script>
26 </html>

  這是段代碼在不停的替換頁面中的a標簽,並且為新的a標簽綁定clcik事件,在事件的回調函數中,引用了上一個事件的e,導致了原本的a標簽即使已經被remove也無法被釋放,仍然保存在內存里。隨着用戶click次數的增多,內存泄露問題也會越來越嚴重。

   所以這個時候,我們就要記得及時清除引用,這段代碼的內存泄露問題是由於事件對象e引起的,在23行,去掉注釋后,e = null 釋放了內層函數對外層函數的變量e指向的對象的引用,使得e以及它引用的dom節點能被釋放,內存泄露問題也就得以解決了。

 

       當然,想寫出高性能的js,還有很多可以仔細研究的地方,而上面的三個習慣是可以在日常的編碼中養成的,也沒有什么替換成本。還有很多良好的習慣,比如減少函數引用,盡量少使用閉包,等,想做到這些方式可能需要較高的替換成本,如果有機會以后再與大家分享吧~。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM