home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

JavaScript/DOMイベント,非同期処理とイベントループとスレッドモデル

JavaScript/DOMイベント,非同期処理とイベントループとスレッドモデル

JavaScript / DOMイベント,非同期処理とイベントループとスレッドモデル
id: 1299 所有者: msakamoto-sf    作成日: 2014-07-14 00:26:30
カテゴリ: HTML JavaScript 

勉強中のメモです。

HTML開発でAjaxなどJavaScriptを活用しようとすると、コールバックを使った非同期処理が活躍します。
ここで一つ疑問に思ったのが、「内部実装としてはイベント処理ってどうしてるんだろう?」という点です。
Win32API開発経験者としては、「やっぱりイベントメッセージのループとかあるのかなぁ・・・」とか、「Ajaxとか非同期I/Oが発生すると、そこだけ別スレッドで処理して、処理が終わるなどのイベントが発生したら、元スレッドのイベントキューにpostしたりしてやりとりしてんのかなぁ」とか。

ということで、調査中の参考リンク、簡単なデモコードなどの仮置き場です。

参考リンク

JavaScriptのDOMイベントの分かりやすい概説

JavaScriptからDOMノードに任意のイベントハンドラを設定し、イベントを発生させるサンプルの解説

JavaScriptのイベントループの内部実装の解説系

html5rocksより:

SpiderMonkeyのThreadSafetyメモ

Javaでコールバック地獄を解決するためのアプローチ:

Javaでのマルチスレッドプログラミング

サンプルコード1

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
  div {
    margin: 5px;
    padding: 5px;
    border: 1px solid red;
  }
  </style>
  <script>
 
  // [start : http://stackoverflow.com/questions/2490825/how-to-trigger-event-in-javascript の丸パクリ]
  // Add an event listener
  document.addEventListener("name-of-event", function(e) {
      console.log(e.detail); // Prints "Example of an event"
  });
 
  // Create the event
  var event = new CustomEvent("name-of-event", { "detail": "Example of an event" });
 
  // Dispatch/Trigger/Fire the event
  document.dispatchEvent(event);
  // [end]
 
  // stopPropagation() のテスト用グローバルフラグ
  window.div2_stop_propagate = false;
  function stop_propagete() {
    window.div2_stop_propagate = true;
  }
 
  function test() {
    // DOM要素が構築された後でないとgetElementById()でDOMノードを取り出せないので、body#onloadイベントで呼び出す。
 
    var p1 = document.getElementById("p1");
    p1.addEventListener("click", function(e) {
      console.log("p1-click", e);
    });
    var div1 = document.getElementById("div1");
    div1.addEventListener("click", function(e) {
      console.log("div1-click", e);
    });
    var div2 = document.getElementById("div2");
    div2.addEventListener("click", function(e) {
      console.log("div2-click", e);
      if (window.div2_stop_propagate) {
        // テスト用グローバルフラグがセットされていれば、stopPropagation()を呼んでみる。
        e.stopPropagation();
      }
    });
    var div3 = document.getElementById("div3");
    div3.addEventListener("click", function(e) {
      console.log("div3-click", e);
    });
  }
  </script>
</head>
<body onload="test()">
  <div id="div1">
    div1
    <div id="div2">
      div2
      <div id="div3">
        div3
        <p id="p1">click</p>
      </div>
    </div>
  </div>
  <hr>
  <input type="button" value="stop at div2" onclick="stop_propagete()">
</body>
</html>

Firefox30での実行結果:

  • 最初に"Example of an event"と表示され、カスタムイベントのテストに成功している。
  • 2行目~5行目までは、"click"をクリックした際に、p1 -> div3 -> div2 -> div1 の順序で順次、イベントが伝播していることを表している。
  • 6行目~8行目は、"stop at div2" をクリックした後 "click" をクリックした様子。div2のところで "stopPropagation()" が呼ばれ、div1のイベントリスナーが動作していない。

Chrome34での実行結果:

  • Firefox30での実行結果と同じ。

IE11での実行結果:

  • 最初のカスタムイベントについては、IE用ではないAPIを使っていたためエラーとなってる。
  • p1の"click", "stop at div2" クリック後のイベント伝播の様子は、Firefox30と同じ。

整理メモ

  • ちょっと古めのサイトによると、JavaScriptはシングルスレッドで動作してるっぽい。
    • そのため、イベント処理はメッセージループでやってる。Win32APIなどのGUIアプリケーションと同じモデル。
  • ただ、HTML5になってDOM構築などのイベントも統合され、最低一つのイベントループ + 1つ以上のタスクキューで処理するようになった。
    • また、ブラウザによってはタスクの種類とブロッキングの特性、順序付などで変更あるらしく、古めの記事のイベントハンドラ処理のサンプルコードが、記事の解説通りの順序ではイベントが発火してないケースも見られた。


プレーンテキスト形式でダウンロード
現在のバージョン : 2
更新者: msakamoto-sf
更新日: 2017-01-07 22:16:46
md5:f544bf5df7c67262c4ca0417c245c736
sha1:63e48afb501be7aa14da4b64eb07b2004edbcdb6
コメント
コメントを投稿するにはログインして下さい。