【JavaScript】JS高速化計画 イベント編

JavaScript

こんにちは、しきゆらです

大層なタイトルをつけましたが、続くかどうかはわかりませんね

あと、内容がお行儀がいいかどうかも保証できませんよっと

 

さて、本題

JSに速度を求めている今日この頃

最近は、少しでも速くなる方法があるのならば、それを使おうと思っています

 

ということで、今回はJSでよく使うであろう

DOMにイベントリスナーを追加する部分を見てみます

 

調べてみると、イベントリスナーを追加するときには

  • addEventListener
  • onXXX

がよく使われていて

両者には違いがあるということはよく書かれています

 

でも、速度の違いは・・・?

ということで簡単なコードを使って検証して見ました

詳しくは、続きから


なんでこんなことするの?

自分で書いたJSのコードが原因でブラウザが固まることが度々起こりました

(前回の記事でも書いたとおり)

そこで、少しでも速く処理できる書き方を求めて色々やっているところです

 

検証する内容

イベントリスナーを追加する方法としてよく使われる以下2つ

  • addEventListener
  • onXXX

合わせて、buttonにリスナーを追加するときはHTMLに直接

<button onclick="hoge()">ボタンを押すと何かが起こす</button>

のように書くので

JSでDOMに属性値を付加する

  • setAttribute

を加えた3種類の動作速度を比較します

 

検証するコード

使用するのは以下

// addEventListenerの検証
function add_event_listener(num) {
     var div = document.createElement("div");
     var time = Date.now();
     for (var i = 0; i < num; i++) {
          div.addEventListener("click", function() {
               console.log("click!!!");
          });
     }
     return Date.now() - time;
}

// onClickの検証
function on_click(num) {
     var div = document.createElement("div");
     var time = Date.now();
     for (var i = 0; i < num; i++) {
          div.onclick = function() {
               console.log("click!!!");
          };
     }
     return Date.now() - time;
}

// setAttributeの検証
function set_attribute(num) {
     var div = document.createElement("div");
     var time = Date.now();
     for (var i = 0; i < num; i++) {
          div.setAttribute("onclick", "console.log('click!!!')");
     }
     return Date.now() - time;
}

// 何度か繰り返し、平均を求める関数
// count: 平均を求めるために繰り返す回数
// num: 上記関数を繰り返す回数
function average(count, num) {
     var add_sum = 0,
     on_sum = 0,
     set_sum = 0;
     var add, on, set;
     for (var i = 0; i < count; i++) {
          add_sum += add_event_listener(num);
          on_sum += on_click(num);
          set_sum += set_attribute(num);
     }
     console.log("average");
     console.log("addEventListener", add_sum / count);
     console.log("onClick", on_sum / count);
     console.log("setAttribute", set_sum / count);
}

 

average(10, 10000)として実行した平均は以下のとおり

単位はミリ秒です

最速のものは太字にしました

 

Mac編

Google Chrome (54.0.2840.71 (64-bit) Mac)

addEventListener 204.2

onClick 35.1

setAttribute 19.1

 

Firefox (51.0a2 (2016-10-29) (64-bit) Mac)

addEventListener 764.3

onClick 16.6

setAttribute 1.9

 

Vivaldi (1.3.582.3 (Developer Build) (64 ビット) Mac)

addEventListener 178.8

onClick 34.5

setAttribute 19.3

 

Safari (10.0.1 (12602.2.14.0.7) Mac)

addEventListener 205

onClick 2.6

setAttribute 3.6

 


Windows編

Google Chrome ( 54.0.2840.71 m (64-bit) Windows)

addEventListener 156.5

onClick 53.8

setAttribute 23.2

 

Firefox (51.0a2 (2016-10-29) (64-bit) Windows)

addEventListener 652.7

onClick 27.4

setAttribute 1.9

 

Firefox (52.0a1 (2016-10-29) (64-bit))

addEventListener 691.1

onClick 24.3

setAttribute 2.4

 

Vivaldi (1.5.648.6 (Official Build) (64 ビット) Windows)

addEventListener 252.6

onClick 53.5

setAttribute 27.6

 

Opera (41.0.2353.46 Stable Windows (32bit))

addEventListener 228.7

onClick 56.2

setAttribute 23.5

 

ついでに、IEとEdgeも期待せずに計測してみました

なんと、IEに関してはコンソールを開くとエラーで落ちるため計測不能

Edgeは「num=10000」だと応答なしになってしまうため

「num=1000」として計測しました

 

以下、参考程度にどうぞ

Edge (39.14955.1000.0 Windows)

addEventListener 756.3

onClick 4.8

setAttribute 14.6

 

結果

結果として、大半のブラウザでは

setAttribute >= onClick >>>>>> addEventListener

という感じになりました

 

SafariとEdgeではdiv.onclickで指定した方が若干速い結果に

AppleとMicrosoftが開発するブラウザが他のブラウザとは異なる結果になったのは面白いですね

 

速度的には「setAttribute」を利用する方が速いですが

読みやすさ的には「onclick」等で指定する方が良さそうな感じですかね

動的にイベントを付加する場合、速度が気になるのであれば

setAttributeかonXXXで指定するのが良さそうです

 

なお、調べてみるとStackOverflowではこんなものもありました

http://stackoverflow.com/questions/6348494/addeventlistener-vs-onclick

複数のイベントをひとつのDOMに指定するときはaddEventListenerが良い

一つしか指定しない場合はonXXXで指定すると良い

(onXXXだと、上書きされて最後に指定したもののみが有効になるため)

ようなことが書かれていました

 

おわり

Posted by shikiyura