javascriptの繰り返し処理の中でhtmlを更新する
for文の中で随時画面を更新する処理を書きたいとき.
(A)
「Jscriptによる繰り返し処理中の画面描画」(1) リッチクライアント & 帳票 − @IT
「ひとつの関数が終わるまでは描画が発生しない」が,for文の中でsetTimeoutを用いて,自身を再度呼び出せば,それっぽくはなる.
ただ,これでは「for文の処理のたびに」ではなく,for文をぶつ切りにして「メソッドが終了するごとに」描画しているので,根本的な解決ではない.
JavaScriptは複数のスレッドで動くわけではないので,無理なのか?
(B)
そこでajax!
http://allabout.co.jp/gm/gc/24213/
Ajaxは、ページ遷移なしでサーバーとデータをやり取りできる、JavaScriptから操作可能なHTTP通信の一種.
for文の中でajaxメソッドやloadメソッドを呼び出す形にすれば,クライアントサイドから繰り返しサーバー側に画面更新依頼が飛びクライアント側に戻ってきて画面が更新される.ただ、
問題1:あくまでシングルスレッド.javascriptの処理が終わったあと,にhtml要素の値を書き換える処理が走るので例えば,for文処理の後にスリープ処理を入れてjavascriptの処理が終了しないようにすると,画面は更新されない.
問題2:また,非同期なのでfor文の順番に描画されることは保証されない。
i=20のHTTP通信がネットワークの関係で通常より時間がかかった場合、i=21の描画
が先に行われる可能性もある。
(C)
そこでWeb Workers!
並列処理を実現!Web Workersを使いこなそう (1/2):連載:人気順に説明する初めてのHTML5開発 - @IT
Web Workers(=ワーカー)を利用することで、JavaScriptコードをマルチスレッドで動かすことが出来る.
問題1→マルチスレッドだから問題なし,かと思いきやボタン押下処理で処理の最後にスリープ処理入れると,処理が終了するまで再描画されない.
これはなぜ?マルチスレッドなら描画されるのでは??
問題2→これはおそらく解決.jsから呼ぶpostMessageの順番とworker側の処理順番が一致していることが保証されていればだけど.
んー,結局Web Workersを使えばとりあえずは良さげだけどやっぱり細かいところはよくわからないや.時間があるときに調べよう.
ちなみに,
①ajaxメソッドやloadメソッドで利用できるファイル
セキュリティー上の理由から、HTMLと同一ドメイン上にあるファイルしか取得できません。
②ajaxメソッドとloadメソッドの違い.
$.load()は、いわゆる「jQuery Ajaxショートハンドメソッド」で、内部的に$.ajaxメソッドを呼んでいます。
参考:http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1182327696
(B),(C)のサンプルコード
(B)for文内でhtmlを再描画するサンプル(Ajaxバージョン)
・クライアント側(html)
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>for文内でhtmlを再描画するサンプル(Ajaxバージョン)</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script src="./multiple.js"></script> </head> <body> <div> <p >Ajaxを用いて,for文内でhtmlを再描画する</p> </div> <div> <p >数値を入れてください。<input type="text" id="num" /></p> <p >ボタンを押してみてください。<button id="a">load</button></p> <p id="my1">ここが書き換わります</p> </div> <div id="foot"> <a href="./sample_button2.html">WebWorkerを用いたサンプルへ</a> </div> <script type="text/javascript"> jQuery(function($){ $("#a").click(function () { var num = document.getElementById("num").value; for(var i = 0; i < num; i++){ $("#my1").load( "./msg.php" ,{ test1:"View has changed " + i + " times!" }); } // alert("for文処理終了!スリープ処理開始(10秒)!") // Sleep(10); // alert("スリープ終了!.javascriptの処理が全て終了しました.") }); }); </script> </html>
・サーバー側(php)
<?php //test1をPOSTで受信 $Data1 = $_POST['test1']; //結合して返す echo($Data1); ?>
(C)for文内でhtmlを再描画するサンプル(WebWorkerバージョン)
・クライアント側(html)
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title>for文内でhtmlを再描画するサンプル(WebWorkerバージョン)</title> <script src="./multiple.js"></script> </head> <body> <div> <p >WebWorkerを用いて,for文内でhtmlを再描画する</p> </div> <div> <p >数値を入れてください。<input type="text" id="num" /></p> <p >ボタンを押してみてください。<button id="a">load</button></p> <p id="my1">ここが書き換わります</p> </div> <div id="foot"> <a href="./sample_button.html">Ajaxを用いたサンプルへ</a> </div> <script type="text/javascript"> // ワーカーの実装チェック if (window.Worker) { // Web Workersに関する処理を記述 document.getElementById("a").addEventListener("click", send, false); var worker = new Worker("multiple.js"); } else { window.alert("このブラウザではWeb Workersは利用できません"); } function send() { var num = document.getElementById("num").value; // ワーカーに入力値を送る worker.postMessage({ "val": num}); alert("for文処理終了!スリープ処理開始(10秒)!") Sleep(10); alert("スリープ終了!.javascriptの処理が全て終了しました.") } // ワーカーからのメッセージ取得時の処理 worker.onmessage = function (event) { document.getElementById("my1").innerHTML = event.data; } </script> </body> </html>
・クライアント側(ワーカーの処理,js)
onmessage = function (event) { var ret = event.data; for(var i = 0; i < ret.val; i++){ // UIスレッド側にメッセージを送付する postMessage("View has changed " + i + " times!"); // Sleep( 1 );//1秒待つ } } function Sleep( T ){ var d1 = new Date().getTime(); var d2 = new Date().getTime(); while( d2 < d1+1000*T ){ //T秒待つ d2=new Date().getTime(); } return; }