Buzzurlの中の人日記

amachang - JavaScript 入門を最初に見たときは見落としてたんだけど、javascript - 勝手に添削 - JavaScript入門with()は徹底的に避けるべしと言われている部分の奇妙なコードが気になって調べて見た。

var nl = document.getElementById('target02').getElementsByTagName('div');
for (var i = 0, l = nl.length; i < l; i ++) {
  var e = nl[i];
  with({e:e})
  setTimeout(function() {
    var box = new Box(e);
    box.start();
  }, i * 500);
}
amachang - JavaScript 入門

なんじゃこの with文? と思ったので色々試したり調べたりしてみた。

正しい挙動

withなし版

var nl = document.getElementById('target02').getElementsByTagName('div');
for (var i = 0, l = nl.length; i < l; i ++) {
  var e = nl[i];
  setTimeout(function() {
    var box = new Box(e);
    box.start();
  }, i * 500);
}

えっ?と一瞬思った。

正しい挙動では、3つの■が順番に動くのに、withなし版では最後の■しか動かない。

でもよくよく考えれば当たり前だ。

感覚の目でよ~く見てみろ!

withなし版がsetTimeoutに渡したクロージャが使うeは、全部同じ実行コンテキスト上のeを参照している。しがたってsetTimeoutがクロージャを呼び出すときにはループは終わってeはnl[nl.length-1]を参照してしまっていて、みんなして最後の■を動かしてしまう。つまりキングクリムゾンによって過程はすっ飛ばされ、結果だけが残る

withを使うと、ループ毎に作られる無名オブジェクト{e:e}がスコープチェーンの先頭に追加されるので、withブロックの中では単にeと書くとブロックローカルなe(=nl[i])を参照できるというわけ。つまりwithを使ってCライクなブロックスコープを実現している。これは知らなかった。

参考:JavaScript でブロックスコープを実現する: Days on the Moon


http://d.hatena.ne.jp/amachang/20060910/1157911122


を見て。



たとえば、以下のようなソースの場合、hello と表示されるのはいつだろうか



setTimeout(function() { alert("hello") }, 10);

~ここに重くて、1秒の時間を有する処理を書く~


答えは 1000 ミリ秒後である。確実に 1000 ミリ秒後である。


[javascript]JavaScript を学ぶ際に一番重要なのに、誤解されがちな setTimeout 系の概念


おっしゃるとおり、僕の知ってる範囲内のJavaScript環境はすべて今実行している関数がブラウザに制御を返すまで、setTimeoutやsetIntervalに割り込まれることはないですね*1


もっと言うと経験則的にはJavaScriptが実行中はブラウザの描画も行われません。だからinnerHTMLに大量のHTMLを突っ込むとかの重い処理を頻発するページは糞重い上に固まってるように見えます。


つまり、経験則的にはブラウザのレンダリング処理を含めてJavaScriptの実行はシングルスレッドで行われるように見えます。これが分かってないと重い処理にプログレスバーをつけようとしたときに、安直な書き方だと期待通りに動かなくてハマります。*2


この、JavaScriptがシングルスレッドなのって仕様で定められてるのですかね?


ECMAScriptの仕様を見れば載ってるのかもしれないけど、Cの仕様にシングルスレッドで動作するなんて書いてないようにECMAScript仕様にもそんなこと書いてないような気がしてちゃんと調べてないです。(「仕様に書いてない」ことを調べるのは面倒だし)


誰かちゃんとしたことを知ってる人がいたら教えて欲しい今日この頃です。




*1:経験的には、「ブラウザに制御を返すまで」なので、重箱の隅をつつくと上の例は1000ミリ秒後とは限らないですね。1秒の時間を要する処理が終わった後、return先がブラウザじゃなくてまた別な関数だったらもっと遅くなり得ます。


*2:一方描画も含めてシングルスレッドだから、JavaScriptの実行中にブラウザや他のスレッドがDOMツリーを変更したりするレースコンディションの可能性を考慮しなくて済むわけですが。


プロフィール
HN:
ajiyoshi
性別:
男性
自己紹介:
プログラマです。
ソーシャルブックマークサービス「Buzzurl」の開発者です。

はてなブックマークカウンタ


旧*「ふっかつのじゅもんがちがいます」カウンタ
Buzzurl

powered by Buzzurl

Twitter

カレンダー
08 2008/09 10
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
最新コメント
[09/08 かすが]
[09/03 セフレ]
[09/03 家出掲示板]
[08/25 出会い系]
[08/05 出会いせ]
最新トラックバック
バーコード
ブログ内検索
忍者ポイント
カウンター
アクセス解析
あわせて読みたい
あわせて読みたい
Powered by ニンジャブログ  Designed by ゆきぱんだ
Copyright c *「ふっかつのじゅもんがちがいます。」 All Rights Reserved
お買い得商品満載「楽市楽座」 / 忍者ブログ