Download - Node.js - JavaScript Thread Programming
Node.js で学ぶ マルチスレッドプログラミング入門
サイボウズ・ラボ / Shibuya.pm
竹迫 良範 @TAKESAKO
Cybozu University 22009/04/06
JavaScript
sleep のない言語 JavaScript
どうやって実現するか?function sleep(msec) { // CPU_100% var t = (new Date()).getTime()-(-msec); while ( (new Date()).getTime() < t ) {} }function sleep(msec) { // LiveConnect Packages.java.lang.Thread.sleep(msec); }
クロスブラウザで sleep を実現(無理矢理)
function sleep(msec) { try { // for IE window.showModalDialog( "javascript:document.write('<script>" + "window.setTimeout(function(){window.close()}," + msec + ");<"\/script>');"); } catch (e) { try { // for Firefox, Opera with LiveConnect Packages.java.lang.Thread.sleep(msec); } catch (e) { // for Safari and others var limit = (new Date()).getTime() - (-msec); while ((new Date()).getTime() < limit) {} } } }
1 秒ごとに表示したい(よくある間違い)
<script>function sleep(msec) { var t = (new Date()).getTime() - (-msec); while ( (new Date()).getTime() < t );}function init() { var body = document.body; sleep(1000); body.innerHTML += "<h1>Hello!</h1>"; sleep(1000); body.innerHTML += "<h2>Hello?</h2>"; sleep(1000); body.innerHTML += "<h3>Hello!?</h3>";};</script><body onload="init()"></body>
問題1: sleep している間 CPU_100% (><)
問題2:3秒後にまとめて表示される
setTimeout で 1 秒ごとに表示する(正解)<script>setTimeout(function(){ var body = document.body; body.innerHTML += "<h1>Hello!</h1>"; setTimeout(function(){ body.innerHTML += "<h2>Hello?</h2>"; setTimeout(function(){ body.innerHTML += "<h3>Hello!?</h3>"; }, 1000); }, 1000);}, 1000);</script>
setTimeout.html – シングルスレッド+遅延
Cybozu University 102009/04/06
}, 1000);
}, 1000);}, 1000);
}, 1000);}, 1000);
Cybozu University 112009/04/06
});});
});});
});
yield
yield で 1 秒ごとに表示<!DOCTYPE html><title>Firefox2.0+ only</title><script type="application/javascript;version=1.7">(function(g){var f=arguments.callee;setTimeout( function(){f(g)},g.next())})((function(){ yield (1000); document.body.innerHTML += "<h1>Hello!</h1>"; yield (1000); document.body.innerHTML += "<h2>Hello?</h2>"; yield (1000); document.body.innerHTML += "<h3>Hello!?</h3>";})());</script>
yield.html – 疑似マルチタスク処理
やりたいこと = 細かく setTimeout を呼ぶ
// こんな風に書けたらいいなぁ(><)
for (var i = 0; i < 10000000; i++) {// すん// ごく// 重たい// 処理// ・・・setTimeout( 次の行 , 0); // ブラウザに処理を戻す
// でもループの中は繰り返したい } // 終了
JavaScript 1.7(Firefox 2.0+)
yield を含む関数は Generator になる
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield;
}}
var g = generator(); // [object Generator]
// まだ document.title は変更されない
Generator#next で次の yield まで実行戻る
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield;
}}
var g = generator(); // [object Generator]g.next(); // document.title = 1;g.next(); // document.title = 2;g.next(); // document.title = 3;
uncaught exception: [object StopIteration]
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield;
}}
var g = generator();for (var j = 1; j <= 998; j++) { g.next() }g.next(); // document.title = 999;g.next(); // document.title = 1000;g.next(); // Error: uncaught exception: // [object StopIteration]
Generator#close
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield;
}}
var g = generator();for (var j = 1; j <= 998; j++) { g.next() }g.next(); // document.title = 999;g.next(); // document.title = 1000;g.close();
yield の引数が next() の戻り値になる
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield (i);
}}
var g = generator();var r;r = g.next(); // r = 1;r = g.next(); // r = 2;r = g.next(); // r = 3;
next() の戻り値をチェックしてきちんと終了
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield (i);
}yield (-1); // 終了条件
}
var g = generator();var r;do { r = g.next() } while (r > 0); // 1...1000g.close();
巨大ループ中で setTimeout(f, 0) が呼べる!
function generator() {for (var i = 1; i <= 1000; i++) {
document.title = i;yield true;
}yield false;
}
function driveGenerator(g) { if (g.next()) { // yield true?
var f = function(){ driveGenerator(g) };setTimeout(f, 0);
} else {g.close(); // yield false
}}
driveGenerator( generator() );
yield + setTimeout イディオムが完成
(function(g){var f=arguments.callee;var t=g.next(); (t<0) ? g.close():setTimeout(function(){f(g)},t)})((function(){
for (var i = 0; i < 10000; i++) { document.title = i; // 重たい処理 yield (0); // ブラウザに一旦処理を戻す( setTimeout ) } yield (-1); // 終了
})());
yield すごい !
Firefox でしか…
でも…
JavaScript1.7 の指定をしないと yield 動かない
<script type="application/javascript;version=1.7">
(function(g){var f=arguments.callee;var t=g.next(); (t<0) ? g.close():setTimeout(function(){f(g)},t)})((function(){
for (var i = 0; i < 10000; i++) { document.title = i; // 重たい処理 yield (0); // ブラウザに一旦処理を戻す( setTimeout ) } yield (-1); // 終了
})());
</script>
28
HTML5 関連Web Workers
HTML5 Web Workers API
main.html worker.js
(3) onmessage = function(e) { var result = e.data + ”!”;
(4) postMessage(result);
(1) var worker = new Worker(“worker.js”);
(2) worker.postMessage(”hello”);
(5) worker.onmessage = function(e) { // DOM 更新処理 window.alert(e.data);
ワーカースレッドの作成
ワーカスレッドを呼び出す UI スレッド
worker.html
<title>HTML5 Web Workers</title><script>var worker = new Worker("worker.js");
worker.onmessage = function(e){ document.body.innerHTML += e.data;}
worker.postMessage("hello");</script>
ワーカスレッドの定義(重たい処理を分離)
worker.jsfunction sleep(msec) { var t = (new Date()).getTime() - (-msec); while ( (new Date()).getTime() < t );}//↓ ワーカ側でメッセージを受信したときの処理onmessage = function(e) { sleep(1000); postMessage("<h1>" + e.data + "!</h1>");}
Web Workers のセキュリティ
Worker スレッドからは
wndow オブジェクトに
触れない!
CPU_100% でも
ブラウザ固まらない!
window.document.write(“hoge”)
UI スレッド
ワーカスレッド
Firefox, Safari, Chrome で動作
Cybozu University 352009/04/06
Node.js拡張
できる?
Cybozu University 362009/04/06
Cybozu University 372009/04/06
jsthread.sourceforge.net
40