タグ「HTML5」が付けられているもの

A. HTML5では再読込を行わないサイトでも個別リンク(permalink)を設定したり、
ブラウザのバックボタンで戻れるようにする為に
ブラウザの履歴やロケーション表示の操作が行えます。

ブラウザの履歴に追加するには
  window.history.pushState(DATA, TITLE, [URL]);
を利用します。

ブラウザのヒストリーが呼ばれた時に呼び出されるイベント
// eventListener style
window.addEventListener("popstate", function(event) {

},false );

// on style
onpopstate = function(event) {

}
event.stateに設定したデータが入っています。
設定したデータもしくはクエリーストリングから
ページの表示内容を適切に変更する事で
AJAXを利用した動的なサイトでも通常ページのような
使い勝手が実現可能です。

var now = 1;

document.addEventListener("DOMContentLoaded", function(){
  // query
  var query = window.location.search;
  var hash = window.location.hash;
  query.match(/^\?n=(\w*)/);
  now = RegExp.$1;
  document.getElementById('now').innerHTML = now;

  // add pushState
  document.getElementById('push').addEventListener("click", function(){
    now++;
    history.pushState(now, document.title, '?n=' + now);
    document.getElementById('now').innerHTML = now;
  }, false);

  // eventListener style
  //window.addEventListener("popstate", function(event) {
  //},false );

  // on style
  onpopstate = function(event) {
    console.log(event);
    if( event.state != null){
      document.getElementById('now').innerHTML = event.state;
      now = event.state;
    }else{
      var query = window.location.search;
      query.match(/^\?n=(\w*)/);
      now = RegExp.$1;
      document.getElementById('now').innerHTML = now;
    }
  }
}, false);


参考サイト:
MDN Manipulating the browser history

[javascript HTML5] Q. Web Workersとは?

A.
HTML5では Web Workersが追加されました。
Web Workersを使うとバックグラウンドで表と平行に処理を
行う事が可能です。
バックグラウンドで動かしたいJavaScriptを別ファイルで作成し
var worker = new Worker("worker1.js");
で呼び出して実行します。

ワーカーに対して通信を行いたい場合
worker.postMessage("MESSAGE");
ワーカーからメッセージを受信するには
// EventListener Style
worker.addEventListener("message",function(event)) {
}, false);

// on Style
worker.onmessage = function(event) {
}
のようにWebMessaagesで通信を行います。

並列で処理を行うので操作の競合を避ける為に
WorkerのJavaScriptでは、DOMやWIndowオブジェクトに
アクセスする事はできません。
このようにWorkerで使えるAPIは限定されていますが
XMLHttpRequestやTimer系は利用することが可能です。

詳しくは以下のサイトで確認できます。
HTML5Rocks Features Available to Workers

実際にワーカーを使ってみます。
ワーカーに数字を渡し、1秒ごとに数字をインクリメントして返却する
という簡単なものです。
親 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebWorkers</title>
<script type="text/javascript">
var worker = new Worker("worker1.js");
var mes = "10";
worker.postMessage(mes);
worker.onmessage = function(event) {
  console.log(event);
  console.log(typeof event.data);
  document.getElementsByTagName("body")[0].innerHTML = event.data;
  if(event.data == parseInt(mes) + 2) worker.terminate();
}
</script>
</head>
<body>
</body>
</html>

worker1.js
onmessage = function(event) {
    var i = parseInt(event.data) || 0;
    self.setInterval( function() {
        postMessage(i++);
    }, 1000 );
};

;
実行結果
js_webworker_1.png

ワーカーをCPUのプロセス数に合わせて複数起動を行い計算処理を分散したり
共有ワーカーを利用して複数のiframeなどで処理を共有させる事も可能です。

参考サイト:
HTML5ROCKS The Basics of Web Worker
whatwg WEB WORKERS
Using web workers
Web Workers を使用して Web アプケーションのユーザビリティーを高める

[javascript HTML5] Q. Server-Sent Eventsとは?

A. Server-Sent Eventsは、サーバーにコネクションを張り続け
サーバーからの応答を待つ一連の動作を簡単に行えるAPIです。
var source = new EventSource(endpoint);
でサーバにアクセスを行い、イベントリスナーで応答を待ちます。
endpointは、オリジン(scheme, domain, portが同じ)でなければいけません。

実際にEventSourceをつかったサンプルをみてみます。

HTMLファイル index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ServerSentEvent</title>
<script type="text/javascript">

var source = new EventSource('/events');

// EventListener Style
source.addEventListener('message', function(e) {
  console.log("MESSAGE");
  console.log(e);
  document.body.innerHTML += e.data + '<br>';
}, false);

// On Style
/*
source.onmessage = function (e) {
  console.log(e.data);
  document.body.innerHTML += e.data + '<br>';
};
*/

source.addEventListener('open', function(e) {
  console.log("OPEN");
  console.log(e);
}, false);

source.addEventListener('error', function(e) {
  // CONNECTING = 0;
  // OPEN = 1;
  // CLOSED = 2;
  if (e.eventPhase == EventSource.CONNECTING) {
    console.log("CONNECTING");
    console.log(e);
  }
  if (e.eventPhase == EventSource.CLOSED) {
    console.log("ERROR");
    console.log(e);
  }
}, false);

</script>
</head>
<body>
</body>
</html>
イベントはaddEventListenerかonスタイル両方で記述する事が可能です。

サーバファイル app.js
var http = require('http');
var fs = require('fs');

http.createServer(function(req, res) {
    console.log(req);
    if (req.headers.accept && req.headers.accept == 'text/event-stream') {
        if (req.url == '/events') {
            res.writeHead(200, {
                'Content-Type': 'text/event-stream',
                'Cache-Control': 'no-cache'
            });
            res.write('data: Server time is: ' + (new Date()) + '\n\n');
            res.end();
        }
    } else {
        // 同じオリジンでないと通信できないので                                           
        // index.htmlもnode.js経由で返す                                            
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(fs.readFileSync('index.html'));
        // 次にコネクションを張る時間
        // res.write("retry: 5000");
        res.end();
    }
} ).listen(10001);
サーバー側はnode.jsで記述してみます。
ここではポート番号10001でサーバーを起動するので
オリジンの同一の為にindex.htmlのリソースもnode.js経由で
応答する事にします。

node.jsでapp.jsを起動する
$ node app.js
node.jsを起動し、ブラウザからindex.htmlにアクセスすると
EventSource('/events')で設定した /event に以下のような要求が来ます

ヘッダー情報(cookieも送信される)
   { host: 'dev.yoshimax.net:10001'
   , 'user-agent': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4'
   , accept: 'text/event-stream'
   , referer: 'http://dev.yoshimax.net:10001/'
   , 'cache-control': 'max-age=0'
   , 'accept-language': 'ja-jp'
   , 'accept-encoding': 'gzip, deflate'
   , cookie: '_redmine_session=BAh7BjoPc2VzcXXXXXXXXX'
   , connection: 'keep-alive'
   }

実行結果は以下のようになります。
js_html5_seversentevent_3.png

ここで応答までの時間や再接続の時間を変更して試してみます。

サーバファイル リトライ5秒 app.js
  res.writeHead(200, {
                    'Content-Type': 'text/event-stream',
                    'Cache-Control': 'no-cache'
  });
  res.write('data: Server time is: ' + (new Date()) + '\n\n');
  // 次にコネクションを張りに来るまでの時間
  res.write("retry: 5000");
  res.end();
}
js_html5_seversentevent_2.png


サーバファイルレスポンス3秒、リトライ1秒 app.js
if (req.url == '/events') {
  // レスポンスまでの時間
  setTimeout(function () {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache'
    });
    res.write('data: Server time is: ' + (new Date()) + '\n\n');
    // 次にコネクションを張りに来るまでの時間
    res.write("retry: 1000");
    res.end();
  }, 3000);
}
js_html5_seversentevent_1.png

参考サイト:
Stream Updates with Server-Sent Events
W3C Server-Sent Events

[javascript HTML5] Q. Web Messageingとは?

A.
HTML5では Web Messageing APIが追加されました。
Web Messageingは、大きく分けてクロスドキュメントメッセージングと
チャンネルメッセージングで分けられています。
どちらも異なるオリジン間において
メッセージ通信が行うことができます。

Web Messageingの仕組みやMessageEventオブジェクトは
Web sockets,WebWorkersやServerSentEventでも利用されており
HTML5周辺技術を学ぶ際にはWeb Messageing APIの理解が役に
立ちますのでしっかりと学習する必要があります。

ここで親window(ドメイン:dev.yoshimax.net)内で読み込んだ
iframe (メイン:sandbox.yoshimax.net)にメッセージを送信し、
iframeから親windowにメッセージの返信を行ってみます。

メッセージを送信するには
window.postMessage(message,origin,port);
メッセージを受信するには
window.addEventListener("message", receiver, false);
の書式で行います。
ここで実際のソースコードを確認してみましょう。
親のHTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Parent</title>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {

  // クリックをしたらfirstFrameにメッセージを送信します。
  var firstBtn = document.getElementById("sendFirstBtn");
  firstBtn.addEventListener("click", function(){
    var fristFrame = document.getElementById("firstFrame");
    firstFrame.postMessage("[from Parent]message","http://sandbox.yoshimax.net");
  }, false);

  // firstFrameからメッセージを受信します。
  window.addEventListener("message", function(e){
    console.log("parent message-----");
    console.log(e);
    if(e.origin == "http://sandbox.yoshimax.net"){
      console.log("parent:" + e.data);
    }
  }, false);

}, false);
</script>
</head>
<body>
<div id="sendFirstBtn" style="border: 1px solid #F00; width:200px;">send message firstF\
rame</div>
<iframe id="firstFrame" width="200" src="http://sandbox.yoshimax.net/tmp/testcode/9-1.html\
"></iframe>
</body>
</html>
iframeのHTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>firstIframe</title>
<script type="text/javascript">
window.addEventListener("message", function(e) {
  console.log("firstframe message-----")
  console.log(e);

  // 受信するドメインを指定する
  if(e.origin == "http://dev.yoshimax.net"){
    // 受信したデータを表示する
    console.log("firstFrame:" + e.data);

    // 親ウインドウにメッセージを送信する
    e.source.postMessage("[from:firstFrame]" + e.data , e.origin);
  }

}, false);
</script>
</head>
<body>
firstIframe
</body>
</html>
実行結果
js_message_1.png

messageのイベントで送られてきたイベントの構造は
HTML5 Web Messaging の 2 Event definitionsで定義されており
このイベントのインターフェースは server-sent events, Web socketsでも
利用されているのでしっかりと把握しよう。

originを適切なドメインにしなかった場合
js_message_2.png

originのドメインの指定が適切ではない場合上記のようなエラーが発生する

参考サイト:
W3C HTML5 Web Messaging
MDN window.postMessage