DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JavaScript性能陷阱小結(附實例說明)
JavaScript性能陷阱小結(附實例說明)
編輯:關於JavaScript     
1.避免使用eval或者Function構造函數
2.避免使用with
3.不要在性能要求關鍵的函數中使用try-catch-finally
4.避免使用全局變量
5.避免在性能要求關鍵的函數中使用for-in
6.使用字符串累加計算風格
7.原操作會比函數調用快
8.設置setTimeout() 和 setInterval() 時傳遞函數名而不是字符串
9.避免在對象中使用不需要的DOM引用
10.最清晰的目標速度,最小化作用域鏈
11.試著在腳本中少使用注釋,避免使用長變量名
12.在當前作用域存儲應用的外部變量
13.使用變量緩存值

1.避免使用eval或者Function構造函數
使用eval或者Function構造函數的代價是非常昂貴的,每次都需要腳本引擎轉換源代碼到可執行代碼。
此外,使用eval處理字符串必須在運行時解釋。

運行緩慢的代碼:
復制代碼 代碼如下:
function addMethod(object, property, code) {
object[property] = new Function(code);
}
addMethod(myObj, 'methodName', 'this.localVar=foo');

運行更快的代碼:
復制代碼 代碼如下:
function addMethod(object, property, func) {
object[property] = func;
}
addMethod(myObj, 'methodName', function () { 'this.localVar=foo'; });

2.避免使用with
盡管很方便,with需要附加的查找引用時間,因為它在編譯的時候並不知道作用域的上下沒。

運行緩慢的代碼:
復制代碼 代碼如下:
with (test.object) {
foo = 'Value of foo property of object';
bar = 'Value of bar property of object';
}

運行更快的代碼:
復制代碼 代碼如下:
var myObj = test.object;
myObj.foo = 'Value of foo property of object';
myObj.bar = 'Value of bar property of object';

3.不要在性能要求關鍵的函數中使用try-catch-finally
try-catch-finally在運行時每次都會在當前作用域創建一個新的變量,用於分配語句執行的異常。
異常處理應該在腳本的高層完成,在異常不是很頻繁發生的地方,比如一個循環體的外面。
如果可能,盡量完全避免使用try-catch-finally。

運行緩慢的代碼:
復制代碼 代碼如下:
var object = ['foo', 'bar'], i;
for (i = 0; i < object.length; i++) {
try {
// do something that throws an exception
} catch (e) {
// handle exception
}
}

運行更快的代碼:
復制代碼 代碼如下:
var object = ['foo', 'bar'], i;
try {
for (i = 0; i < object.length; i++) {
// do something
}
} catch (e) {
// handle exception
}

4.避免使用全局變量
如果你在一個函數或者其它作用域中使用全局變量,腳本引擎需要遍歷整個作用域去查找他們。
全局作用域中的變量在腳本的生命周期裡都存在,然後局部范圍的會在局部范圍失去的時候被銷毀。

運行緩慢的代碼:
復制代碼 代碼如下:
var i,
str = '';
function globalScope() {
for (i=0; i < 100; i++) {
str += i; // here we reference i and str in global scope which is slow
}
}
globalScope();

運行更快的代碼:
復制代碼 代碼如下:
function localScope() {
var i,
str = '';
for (i=0; i < 100; i++) {
str += i; // i and str in local scope which is faster
}
}
localScope();

5.避免在性能要求關鍵的函數中使用for-in
for-in循環需要腳本引擎建立一張所有可枚舉屬性的列表,並檢查是否與先前的重復。
如果你的for循環作用域中的代碼沒有修改數組,可以預先計算好數組的長度用於在for循環中迭代數組。

運行緩慢的代碼:
復制代碼 代碼如下:
var sum = 0;
for (var i in arr) {
sum += arr[i];
}

運行更快的代碼:
復制代碼 代碼如下:
var sum = 0;
for (var i = 0, len = arr.length; i < len; i++) {
sum += arr[i];
}

6.使用字符串累加計算風格
使用+運算會在內存中創建一個新的字符串並把連接的值賦給它。僅僅是將這個結果賦值給一個變量。
為了避免連接結果的中間變量,可以使用+=來直接賦值結果。

運行緩慢的代碼:
復制代碼 代碼如下:
a += 'x' + 'y';

運行更快的代碼:
復制代碼 代碼如下:
a += 'x'; a += 'y';

7.原操作會比函數調用快
可以考慮在性能要求關鍵的循環和函數中使用可以替代的原操作。
運行緩慢的代碼:
復制代碼 代碼如下:
var min = Math.min(a, b);
arr.push(val);

運行更快的代碼:
復制代碼 代碼如下:
var min = a < b ? a : b;
arr[arr.length] = val;

8.設置setTimeout() 和 setInterval() 時傳遞函數名而不是字符串
如果你傳遞一個字符串到setTimeout() 或者 setInterval()中,字符串將會被eval計算而導致緩慢。
使用一個匿名函數包裝來代替,這樣在編譯的時候就可以被解釋和優化。

運行緩慢的代碼:
setInterval('doSomethingPeriodically()', 1000);
setTimeOut('doSomethingAfterFiveSeconds()', 5000);

運行更快的代碼:
復制代碼 代碼如下:
setInterval(doSomethingPeriodically, 1000);
setTimeOut(doSomethingAfterFiveSeconds, 5000);

9.避免在對象中使用不需要的DOM引用

不要這麼做:

復制代碼 代碼如下:
var car = new Object();
car.color = "red";
car.type = "sedan"

更好的一種形式:

復制代碼 代碼如下:
var car = {
color : "red";
type : "sedan"
}

10.最清晰的目標速度,最小化作用域鏈

低效率方法:
復制代碼 代碼如下:
var url = location.href;

一種高效形式:
復制代碼 代碼如下:
var url = window.location.href;

11.試著在腳本中少使用注釋,避免使用長變量名
盡可能的保證注釋少或者避免使用注釋,特別是在函數,循環以及數組中。
注釋不必要的減緩腳本執行並且增加了文件大小。比如:

不建議的形式:

復制代碼 代碼如下:
function someFunction()
{
var person_full_name="somename"; /* stores the full name*/
}

更好的寫法:
復制代碼 代碼如下:
function someFunction()
{
var name="somename";
}

12.在當前作用域存儲應用的外部變量
當一個函數被執行的運行上下問被穿件,一個活動的對象會包含所有局部變量會被推到上下文鏈的前面。
在作用域鏈中,最慢的是清楚的識別標識符,意味著局部變量是最快的。存儲頻繁使用的外部變量讀和寫都會明顯的加快。這對於全局變量和其他深層次的標識符查找特別明顯。
同樣,在當前作用域中的變量(var myVar)比對象像屬性的訪問速度快(this.myVar)。

運行緩慢的代碼:

復制代碼 代碼如下:
function doSomething(text) {
var divs = document.getElementsByTagName('div'),
text = ['foo', /* ... n ... */, 'bar'];
for (var i = 0, l = divs.length; i < l; i++) {
divs[i].innerHTML = text[i];
}
}

運行更快的代碼:

復制代碼 代碼如下:
function doSomethingFaster(text) {
var doc = document,
divs = doc.getElementsByTagName('div'),
text = ['foo', /* ... n ... */, 'bar'];
for (var i = 0, l = divs.length; i < l; i++) {
divs[i].innerHTML = text[i];
}
}

如果你需要訪問一個元素(如 head)在一個大的循環中,使用一個本地的DOM訪問(如例子中的get)會更快。
運行更快的代碼:
復制代碼 代碼如下:
function doSomethingElseFaster() {
var get = document.getElementsByTagName;
for (var i = 0, i < 100000; i++) {
get('head');
}
}

13.使用變量緩存值
在做重復工作的地方使用局部變量緩存值。
下面的一組例子表明了存儲值到局部變量的廣泛意義。

例子1.計算執行前在循環體內使用變量存儲數學函數
錯誤的方法:
復制代碼 代碼如下:
var d=35;
for (var i=0; i<1000; i++) {
y += Math.sin(d)*10;
}

更好的處理:
復制代碼 代碼如下:
var d = 55;
var math_sind = Math.sin(d)*10;
for (var i=0; i<1000; i++) {
y += math_sind;
}

例子2.保存數組的長度在循環中使用
糟糕的處理:
數組的長度每次都會被重復計算
復制代碼 代碼如下:
for (var i = 0; i < arr.length; i++) {
// do something
}

更好的改進:
更好的方法是保存數組的長度
復制代碼 代碼如下:
for (var i = 0, len = arr.length; i < len; i++) {
// do something
}

總的來說,如果已經做了一次,我們就不需要重復的做不必要的工作。例如,作用域或者函數中多次使用到計算的一個表達式的值,保存到變量可以使它多次被使用,否則我們會過頭的聲明一個變量並賦值然後只適用一次。所以請記住這些。

補充說明:
第2點
順便說一下JS主要不是編譯的是解釋的. 雖說不影響表達,但學術還是嚴謹點好.

第6點這是不是格式搞亂了?
a += ‘x' + ‘y';
運行更快的代碼:

a += 'x'; a += 'y';

9.避免在對象中使用不需要的DOM引用
new Object也是DOM引用?
這個應該是說不要輕意使用new Object()還有new Array(), 以及new Function() 一般情況使用 {...}, [...], f = function(..){...} 即:
這和上面那一點應該說的是一回事.

最後補充一個少用 位運算, 因為js的所有數值運算最後(到JS引擎這層)都是全部轉得浮點來算的..所以位運算可能反而更慢.
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved