首頁  >  文章  >  web前端  >  編寫高效能的 JavaScript

編寫高效能的 JavaScript

黄舟
黄舟原創
2017-02-21 11:45:441577瀏覽



編寫高效能的 JavaScript

。本文的初衷是想介紹如何利用些簡單的程式碼小技巧就能促進JavaScript編譯器的最佳化進程從而提升程式碼運行效率。特別是在遊戲這種對於垃圾回收速度要求較高,你效能稍微差點用戶就能見到白屏的地方。

Monomorphism:單態性

JavaScript中允許函數呼叫時候傳入動態參數,不過就以簡單的2參數函數為例,當你的參數型別、參數數目與回傳類型動態呼叫時才能決定,編譯器需要更多的時間來解析。編譯器自然地希望能夠處理那些單態可預測的資料結構、參數統計等。

function example(a, b) {
  // we expect a, b to be numeric
  console.log(++a * ++b);
};

example(); // bad
example(1); // still bad
example("1", 2); // dammit meg

example(1, 2); // good

Constants:常數

使用常數能讓編譯器在編譯時即完成變數的值替換:

const a = 42; // we can easily unfold this
const b = 1337 * 2; // we can resolve this expression
const c = a + b; // still can be resolved
const d = Math.random() * c; // we can only unfold 'c'

// before unfolding
a;
b;
c;
d;

// after unfolding
// we can do this at compile time!
42;
2674;
2716;
Math.random() * 2716;

Inlining:內聯

JIT編譯器能夠找出你的程式碼中被執行次數最多的部分,將你的程式碼分割成多個小的程式碼區塊能夠有助於編譯器在編譯時將這些程式碼區塊轉換為內聯格式然後增加執行速度。

Data Types:資料類型

盡可能地多用Numbers與Booleans類型,因為他們與其他類似於字串等原始類型相比效能表現更好。使用字串類型可能會帶來額外的垃圾回收消耗。

const ROBOT = 0;
const HUMAN = 1;
const SPIDER = 2;

let E_TYPE = {
  Robot: ROBOT,
  Human: HUMAN,
  Spider: SPIDER
};

// bad
// avoid uncached strings in heavy tasks (or better in general)
if (entity.type === "Robot") {
  
}

// good
// the compiler can resolve member expressions
// without much deepness pretty fast
if (entity.type === E_TYPE.Robot) {
  
}

// perfect
// right side of binary expression can even get unfold
if (entity.type === ROBOT) {
  
}

Strict & Abstract Operators

盡可能使用 === 這個嚴格比較操作符而不是 == 運算子。使用嚴格比較操作符能夠避免編譯器進行類型推導與轉換,從而提高一定的效能。

Strict Conditions

JavaScript中的if語句也非常靈活,你可以直接在 if(a) then bla 這個類型的條件選擇語句中傳入隨意類似的a值。不過這種情況下,就像上文提及的嚴格比較操作符與寬鬆比較操作符一樣,編譯器需要將其轉換為多個資料型別進行比較,而不能立刻得出結果。當然,這並不是一味的反對使用簡寫方式,而是在非常強調性能的場景,還是建議做好每一個細節的優化:

let a = 2;

// bad
// abstracts to check in the worst case:
// - is value equal to true
// - is value greater than zero
// - is value not null
// - is value not NaN
// ..
if (a) {
 // if a is true, do something 
}

// good
if (a === 2) {
  // do sth 
}

// same goes for functions
function b() {
  return (!false);
};

if (b()) {
  // get in here slow
}

if (b() === true) {
  // get in here fast
  // the compiler knows a specific value to compare with
}

Arguments

盡可能避免使用arguments [index]方式進行參數獲取,並且盡量避免修改傳入的參數變數:

function mul(a, b) {
  return (arguments[0]*arguments[1]); // bad, very slow
  return (a*b); // good
};

function test(a, b) {
  a = 5; // bad, dont modify argument identifiers
  let tmp = a; // good
  tmp *= 2; // we can now modify our fake 'a'
};

Toxicity:這些關鍵字有毒

Toxicity

#如下列舉的幾個語法特性會影響最佳化進程:

  • eval

  • #with

  • ##try/catch

同時盡量避免在函數內宣告函數或閉包,可能在大量的運算中導致過多的垃圾回收操作。

Objecs

Object實例通常會共用隱類,因此當我們存取或設定某個實例的未預先定義變數值的時候會建立一個隱類。

// our hidden class 'hc_0'
class Vector {
  constructor(x, y) {
    // compiler finds and expects member declarations here
    this.x = x;
    this.y = y;
  }
};

// both vector objects share hidden class 'hc_0'
let vec1 = new Vector(0, 0);
let vec2 = new Vector(2, 2);

// bad, vec2 got hidden class 'hc_1' now
vec2.z = 0;

// good, compiler knows this member
vec2.x = 1;

Loops

盡可能的快取陣列長度的計算值,並且盡可能在同一個陣列中存放單一類型。避免使用 for-in 語法來遍歷某個數組,因為它真的很慢。另外,continue與break語句在迴圈中的表現也是不錯的,這點使用的時候不用擔心。另外,盡可能將短小的邏輯部分拆分到獨立的函數中,這樣更有利於編譯器進行最佳化。另外,使用前綴自增表達式,也能帶來小小的效能提升。 (++i代替i++)

let badarray = [1, true, 0]; // bad, dont mix types
let array = [1, 0, 1]; // happy compiler

// bad choice
for (let key in array) {
  
};

// better
// but always try to cache the array size
let i = 0;
for (; i < array.length; ++i) {
  key = array[i];
};

// good
let i = 0;
let key = null;
let length = array.length;
for (; i < length; ++i) {
  key = array[i];
};

drawImage

draeImage函數算是最快的2D Canvas API之一了,不過我們需要注意的是如果為了圖方便省略了全參數傳入,也會增加效能損耗:

// bad
ctx.drawImage(
  img,
  x, y
);

// good
ctx.drawImage(
  img,
  // clipping
  sx, sy,
  sw, sh,
  // actual stuff
  x, y,
  w, h
);

// much hax
// no subpixel rendering by passing integers
ctx.drawImage(
  img,
  sx|0, sy|0,
  sw|0, sh|0,
  x|0, y|0,
  w|0, h|0
);

 

以上就是寫高效能的JavaScript的內容,更多相關內容請關注PHP中文網(www.php.cn)!

 


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn