javascript效能優化(8)
Programming Practices 程式設計實踐
避免二次評估
JavaScript 與許多指令碼語言一樣,允許你在程式中獲取一個包含程式碼的字串然後執行它。有四種標準 方法可以實現:eval(),Function()構造器,setTimeout()和 setInterval()。每個函式允許你傳入一串 JavaScript 程式碼,然後執行它。例如
var num1 = 5, num2 = 6, //eval_r() evaluating a string of code
result = eval("num1 + num2"), //Function() evaluating strings of code
sum = new Function("arg1", "arg2", "return arg1 + arg2"); //setTimeout()evaluating a string of code
setTimeout("sum = num1 + num2", 100); //setInterval() evaluating a string of code
setInterval("sum = num1 + num2", 100);
結果都是11
避免二次評估是實現優化的 JavaScript 執行時效能的關鍵。
作為一個比較點,不同瀏覽器上訪問一個陣列項所佔用的時間各有不同,但如果使用 eval()訪問其結 果將大相徑庭。例如:
//faster
var item = array[0];
//slower
var item = eval_r("array[0]");
若使用 eval()代替直接程式碼訪問 10’000 個陣列項,在不同瀏覽器上的差異非常巨大。是因為每次呼叫 eval()時要建立一個新的解釋/編譯例項。同樣的過程 也發生在 Function(),setTimeout()和 setInterval()上,自動使程式碼執行速度變慢。
大多數情況下,沒必要使用 eval()或 Function(),如果可能的話,儘量避免使用它們。至於另外兩個函 數,setTimeout()和 setInterval(),建議第一個引數傳入一個函式而不是一個字串。例如:
setTimeout(function () {
sum = num1 + num2;
}, 100);
setInterval(function () {
sum = num1 + num2;
}, 100);
使用物件/陣列直接量
典型的物件建立和賦值是這樣的:
//create an object
var myObject = new Object();
myObject.name = "Nicholas";
myObject.count = 50;
myObject.flag = true;
myObject.pointer = null;
//create an array
var myArray = new Array();
myArray[0] = "Nicholas";
myArray[1] = 50;
myArray[2] = true;
myArray[3] = null;
但是,直接量賦值很快。作為一個額外的好處,直接量在你的程式碼中佔 用較少空間,所以整個檔案尺寸可以更小。
//create an object
var myObject = {name: "Nicholas", count: 50, flag: true, pointer: null};
//create an array
var myArray = ["Nicholas", 50, true, null];
不要重複工作
也許常見的重複工作型別是瀏覽器檢測。大量程式碼依賴於瀏覽器的功能。以事件控制程式碼的新增和刪除為 例,典型的跨瀏覽器程式碼如下:
function addHandler(target, eventType, handler) {
if (target.addEventListener) { //DOM2 Events
target.addEventListener(eventType, handler, false);
} else { //IE
target.attachEvent("on" + eventType, handler);
}
}
function removeHandler(target, eventType, handler) {
if (target.removeEventListener) { //DOM2 Events
target.removeEventListener(eventType, handler, false);
} else { //IE
target.detachEvent("on" + eventType, handler);
}
}
乍一看,這些函式為實現它們的目的已經足夠優化。隱藏的效能問題在於每次函式呼叫時都執行重複工 作。每一次,都進行同樣的檢查,看看某種方法是否存在。如果你假設 target 唯一的值就是 DOM 物件, 而且使用者不可能在頁面載入時魔術般地改變瀏覽器,那麼這種判斷就是重複的。如果 addHandler()一上來 就呼叫addEventListener()那麼每個後續呼叫都要出現這句程式碼。在每次呼叫中重複同樣的工作是一種浪費, 有多種辦法避免這一點。
延遲載入
第一種消除函式中重複工作的方法稱作延遲載入。延遲載入意味著在資訊被使用之前不做任何工作。在
前面的例子中,不需要判斷使用哪種方法附加或分離事件控制程式碼,直到有人呼叫此函式。使用延遲載入的函
數如下:
function addHandler(target, eventType, handler) {
//overwrite the existing function
if (target.addEventListener) { //DOM2 Events
addHandler = function (target, eventType, handler) {
target.addEventListener(eventType, handler, false);
};
} else { //IE
addHandler = function (target, eventType, handler) {
target.attachEvent("on" + eventType, handler);
};
}
//call the new function
addHandler(target, eventType, handler);
}
function removeHandler(target, eventType, handler) {
//overwrite the existing function
if (target.removeEventListener) { //DOM2 Events
removeHandler = function (target, eventType, handler) {
target.addEventListener(eventType, handler, false);
};
} else { //IE
removeHandler = function (target, eventType, handler) {
target.detachEvent("on" + eventType, handler);
};
}
//call the new function
removeHandler(target, eventType, handler);
}
這兩個函式依照延遲載入模式實現。這兩個方法第一次被呼叫時,檢查一次並決定使用哪種方法附加或分離事件控制程式碼。然後,原始函式就被包含適當操作的新函式覆蓋了。後呼叫新函式並將原始引數傳給它。以後再呼叫 addHandler()或者 removeHandler()時不會再次檢測,因為檢測程式碼已經被新函式覆蓋了。
呼叫一個延遲載入函式總是在第一次使用較長時間,因為它必須執行檢測然後呼叫另一個函式以完成任務。但是,後續呼叫同一函式將快很多,因為不再執行檢測邏輯了。延遲載入適用於函式不會在頁面上立即被用到的場合。
條件預載入
它在指令碼載入之前提前進行檢查,而不等待函式呼叫。 這樣做檢測仍只是一次,但在此過程中來的更早。例如:
var addHandler = document.body.addEventListener ? function (target, eventType, handler) {
target.addEventListener(eventType, handler, false);
} : function (target, eventType, handler) {
target.attachEvent("on" + eventType, handler);
};
var removeHandler = document.body.removeEventListener ? function (target, eventType, handler) {
target.removeEventListener(eventType, handler, false);
} : function (target, eventType, handler) {
target.detachEvent("on" + eventType, handler);
};
這個例子檢查 addEventListener()和 removeEventListener()是否存在,然後根據此資訊指定合適的函式。 三元操作符返回 DOM 級別 2 的函式,如果它們存在的話,否則返回 IE 特有的函式。然後,呼叫 addHandler() 和 removeHandler()同樣很快,雖然檢測功能提前了。
條件預載入確保所有函式呼叫時間相同。其代價是在指令碼載入時進行檢測。預載入適用於一個函式馬上 就會被用到,而且在整個頁面生命週期中經常使用的場合。
位操作運算子
計算對 2 取模,需要用這個數除以 2 然後檢視餘數。如果你看到 32 位數字的底層(二進位制)表示法, 你會發現偶數的低位是 0,奇數的低位是 1。如果此數為偶數,那麼它和 1 進行位與操作的結果就是 0; 如果此數為奇數,那麼它和 1 進行位與操作的結果就是 1。也就是說上面的程式碼可以重寫如下:
for (var i = 0, len = rows.length; i < len; i++) {
if (i & 1) {
className = "odd"; //奇數
} else {
className = "even";//偶數
}
//apply class
}
比取餘運算要快;i%2
;
第二種使用位操作的技術稱作位掩碼。位掩碼在電腦科學中是一種常用的技術,可同時判斷多個布林 選項,快速地將數字轉換為布林標誌陣列。掩碼中每個選項的值都等於 2 的冪。例如:
var OPTION_A = 1;
var OPTION_B = 2;
var OPTION_C = 4;
var OPTION_D = 8;
var OPTION_E = 16;
var options = OPTION_A | OPTION_C | OPTION_D;
//is option A in the list?
if (options & OPTION_A) {
//do something
console.log(options);
}
//is option B in the list?
if (options & OPTION_D) {
//do something
console.log(options);
}
結果:13 13
像這樣的位掩碼操作非常快,正因為前面提到的原因,操作發生在系統底層。如果許多選項儲存在一起 並經常檢查,位掩碼有助於加快整體效能。
原生方法
- 儘量使用Math物件,避免大量的數學邏輯;
- 使用原生的選擇器 API;如 querySelector()和 querySelectorAll();
Summary 總結
- 通過避免使用 eval_r()和 Function()構造器避免二次評估。此外,給 setTimeout()和 setInterval()傳遞函式參 數而不是字串引數
- 建立新物件和陣列時使用物件直接量和陣列直接量。它們比非直接量形式建立和初始化更快。
- 避免重複進行相同工作。當需要檢測瀏覽器時,使用延遲載入或條件預載入。
- 當執行數學運算時,考慮使用位操作,它直接在數字底層進行操作。
- 原生方法總是比 JavaScript 寫的東西要快。儘量使用原生方法。
相關文章
- javascript效能優化JavaScript優化
- Javascript 效能優化JavaScript優化
- javascript效能優化(7)JavaScript優化
- javascript效能優化(9)JavaScript優化
- javascript效能優化(10)JavaScript優化
- 前端效能優化JavaScript篇前端優化JavaScript
- JavaScript 操作DOM效能優化JavaScript優化
- JavaScript 效能優化技巧分享JavaScript優化
- JavaScript 效能優化殺手JavaScript優化
- javascript效能優化技巧介紹JavaScript優化
- javascript指令碼的效能優化JavaScript指令碼優化
- CSS效能優化的8個技巧CSS優化
- V8 效能優化殺手優化
- 幾個 JavaScript 效能優化小 TipJavaScript優化
- 淺談JavaScript程式碼效能優化JavaScript優化
- JavaScript 程式碼效能優化總結JavaScript優化
- 前端效能優化(三)——傳統 JavaScript 優化的誤區前端優化JavaScript
- JavaScript 前端效能優化之事件節流JavaScript前端優化事件
- JavaScript 前端效能優化之事件防抖JavaScript前端優化事件
- 淺談JavaScript程式碼效能優化2JavaScript優化
- JavaScript效能優化小知識總結JavaScript優化
- JavaScript資料訪問效能優化方案JavaScript優化
- JavaScript無阻塞載入效能優化方案JavaScript優化
- 【前端效能優化】高效能JavaScript讀書筆記前端優化JavaScript筆記
- Web效能優化系列:10個JavaScript效能提升的技巧Web優化JavaScript
- 【前端效能優化】vue效能優化前端優化Vue
- Web 效能優化:理解及使用 JavaScript 快取Web優化JavaScript快取
- javascript程式碼效能優化簡單介紹JavaScript優化
- JavaScript 效能優化的小知識總結JavaScript優化
- JavaScript 的效能優化:載入和執行JavaScript優化
- JavaScript的效能優化:載入和執行JavaScript優化
- 從 JavaScript 陣列去重談效能優化JavaScript陣列優化
- 面向前端開發者的V8效能優化前端優化
- 【譯】Web 效能優化:理解及使用 JavaScript 快取Web優化JavaScript快取
- [譯] JavaScript 如何工作:渲染引擎和效能優化技巧JavaScript優化
- 效能優化優化
- 效能優化案例-SQL優化優化SQL
- 【效能優化】ORACLE資料庫效能優化概述優化Oracle資料庫