ブラウザのJavaScriptはシングルスレッドで動いている。
そんなことは知っている。
いや、知ってはいてもちょいちょい忘れてていけてないコードを書いちゃうこともあるのだ。
JavaScriptでのWebSocketの使い方は以下のようなコードになる
var ws = new WebSocket("ws:..."); ws.onopen = function(e) { ...}; ws.onmessage = function(e) { ...};
このコードを見て「onopenをバインドするよりも前に接続が確立しちゃったらどうなるんだろう?」と疑問に思わないだろうか?
でも、実際にはそんなことは起こらない。何故ならWebSocketの接続が行われるのはコンストラクタを実行している関数の処理を抜けた後だから。
このことは以下のようなコードで検証できる。
function init() { console.log("Start init: " + new Date().getTime()); var ws = new WebSocket("ws:..."); ws.onopen = function(e) { console.log("WebSocket open: " + new Date().getTime()); } for (var i=0; i<1000000; i++) { var dummy = new Date(); } console.log("End init: " + new Date().getTime()) }
空ループを回さなければ20ms以下で接続が確立するが、このコードではループが終了するまで接続は行われないので数秒のタイムラグがある。
言い換えれば「End init」のログは常に「WebSocket open」よりも先に出力される。
(ただしFirefoxでFireBugを動かしていると途中で「スクリプトが応答していません。」のようなダイアログが表示されることがあり、その場合はそこに割り込んでWebSocketの接続が行われる。)
何が言いたいかと言うと、
function init() { var ws = new WebSocket("ws:..."); //なんか重たい処理 ws.send("hoge"); }
のようなコードは途中にどれだけ重たい処理があっても必ず失敗するのでちゃんとonopenを使おうという話でした。