v8層面
var person = {
multiply:function (a,b) {
return a*b;
},
name:`gcy`
}
for(let i=0;i<1000;i++){
person.multiply(i,i);
}
說明 定義物件的時候,最好一開始就初始化好物件的屬性,不要動態的新增。
在java或c++靜態語言中,類的資訊是確定的,所以每個物件包含哪些成員和成員在物件中偏移量在編譯階段確定,基地址和偏移地址就可以快速的訪問物件內部資訊。
js中物件屬性可以動態新增或刪除,為了實現按照索引的方式快速訪問成員,v8內部產生了一種資料結構即隱藏類(基於執行中的物件分類)。動態新增屬性會造成隱藏類派生,同時無法使用v8優化(針對熱點程式碼,v8會使用優化編譯器,目前預設是 CrankShaft,比如上述示例for迴圈中會進行引數預測,標記為整形)後的程式碼。另外推薦在編寫程式碼的時候進行不要讓程式進行型別推導,方案有flow和typeScript,flow我用過,侵入性低、容易上手,推薦使用,這樣做的目的一方面在大專案協作過程中可以使程式碼具有良好的維護性,其次還可以提高v8執行效率,避免優化回退(重新執行函式->ast->機器碼過程)。
c++層面
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
//isolate V8 runtime
args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hw gcy"));
}
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "hw", Method); //向外匯出方法
}
NODE_MODULE(addon, init)
<!--使用-->
const binding = require(`./build/Release/binding`);
console.log(binding.hw());
c++擴充node 模組(針對底層擴充和效率要求極高場景)
為什麼使用c++編寫node?
http://www.tuicool.com/articl…
tools層面
Prepack (js執行效率優化)
webpack2 (tree-shaking) 體積優化
記憶體層面
var vm=new WeakMap();
var b=new Object();
vm.set(b,{`name`:`gcy`});
b=null;
vm.get(b);
使用weakMap,在key對應的物件,可能會消失的情況下,會減少記憶體洩漏發生的概率,合理的利用和使用記憶體的方式之一。
參考連結 weakmap
dom層面
最小化dom訪問次數,注意重繪和重排,儘可能在JavaScript端處理,`離線操作DOM tree`,使用快取,減少訪問佈局資訊次數
案例一
不要頻繁獲取佈局資訊,因為其會導致渲染佇列重新整理,例如常用的offsetTop屬性,offsetWidth屬性等等。
案例二
批量修改dom時,使元素脫離文件流(!important),應用多重改變邏輯,然後再把元素放回文件中
脫離文件流的三種方式
- 隱藏元素,應用修改,重新顯示
- fragment方式額外建立DOM tree
- 原始element copy,然後修改後,在 replace
- 動畫元素使用絕對定位的方式
- virtual dom方式,操作vnode,diff後在實際元素上應用最終邏輯
使用事件委託減少事件處理器數量(本質上是利用冒泡機制,比較簡單,不在舉例)
js層面
案例一
function ProcessArray(items,process,callback) {
let todo=items.concat();
setTimeout(function () {
process(todo.shift());
//如果還有待處理元素,建立另外一個定時器
if(todo.length>0){
setTimeout(arguments.callee,20);
}else {
callback(items);
}
},20)
}
說明 上面優化的目的是為了避免browser的鎖定,還可以使用web work的方式
var worker=new Worker(`process.js`);
worker.onmessage=function (event) {
//logic
}
worker.postMessage(items)
// process.js
self.onmessage=function (event) {
var ans=process(event.data);
self.postMessage(ans);
}
案例二
var num1=5;
var num2=6;
eval("num1+num2");
new Function("arg1","arg2","return arg1+arg2");
setTimeout("sum1=num1+num2",100)
說明 避免雙重求值
案例三
function fact1(n) {
if(n==0)return 1;
return n*fact1(n-1);
}
-----------------------------------
fact2(n,acc=1){
if(n==0)return acc;
return fact2(n-1,acc*n);
}
說明 尾遞迴的優化的目的是為了防止棧溢位
關於js方面的技巧蠻多的,比如延遲載入,位操作,throttle等等,不在一一列舉。
總結
js優化這篇文章小部分是工作的總結,大部分是看書(高效能js和NODE進階之路等)後的理解和總結,其實點蠻多的,以後再補充吧。