[解決済み] JavaScriptはシングルスレッドであることが保証されていますか?
質問
JavaScript は、最近のブラウザの実装ではすべてシングルスレッドであることが知られていますが、これは何らかの規格で規定されているのでしょうか、それとも単なる伝統なのでしょうか?JavaScript は常にシングルスレッドであると仮定しても全く問題ないのでしょうか?
どうすれば解決するの?
いい質問ですね。はい」と答えたいところですが できないんです。
JavaScriptは通常、スクリプト(*)から見える実行スレッドが1つであると考えられており、インラインスクリプト、イベントリスナー、タイムアウトが入力されても、ブロックや関数の終わりから戻るまで完全に制御されたままです。
(*: ブラウザが本当に1つのOSスレッドを使用してJSエンジンを実装しているのか、それともWebWorkersによって他の限定されたスレッドオブエクスキューションが導入されているのかという問題は無視します)。
しかし、現実にはこの とは言い切れない ということです。
最も一般的なケースは、即時イベントです。ブラウザは、あなたのコードによってイベントが発生したときに、すぐにこれを発生させます。
var l= document.getElementById('log');
var i= document.getElementById('inp');
i.onblur= function() {
l.value+= 'blur\n';
};
setTimeout(function() {
l.value+= 'log in\n';
l.focus();
l.value+= 'log out\n';
}, 100);
i.focus();
<textarea id="log" rows="20" cols="40"></textarea>
<input id="inp">
の結果
log in, blur, log out
IE 以外では これらのイベントは、単に
focus()
を直接呼び出したために起こるかもしれません。
alert()
とか、ポップアップ・ウィンドウを開くとか、フォーカスを移動させるものは何でもいいんです。
これは、他のイベントも発生させることができます。例えば
i.onchange
リスナーで、入力に何かを入力した後
focus()
の呼び出しでフォーカスが解除され、ログの順番は
log in, change, blur, log out
ただし、Operaでは
log in, blur, log out, change
となり、IEでは(さらに説明不要の)
log in, change, log out, blur
.
同様に
click()
を提供する要素に対して
onclick
ハンドラは、すべてのブラウザで直ちに実行されます (少なくともこれは一貫しています!)。
(私は、直接
on...
イベントハンドラプロパティを使用しても同じことが起こりますが、ここでは
addEventListener
と
attachEvent
.)
を実行したにもかかわらず、コードがスレッド化されている間にイベントが発生する可能性がある状況もたくさんあります。 何も を呼び起こすことができます。例を挙げますと
var l= document.getElementById('log');
document.getElementById('act').onclick= function() {
l.value+= 'alert in\n';
alert('alert!');
l.value+= 'alert out\n';
};
window.onresize= function() {
l.value+= 'resize\n';
};
<textarea id="log" rows="20" cols="40"></textarea>
<button id="act">alert</button>
ヒット
alert
をクリックすると、モーダルダイアログボックスが表示されます。そのダイアログを解除するまで、もうスクリプトは実行されませんね?いいえ。メインウィンドウのサイズを変更すると、次のようになります。
alert in, resize, alert out
をテキストエリアに入力します。
Linuxではウィンドウのサイズを好きなだけ変更できます。Windowsではそう簡単ではありませんが、画面の解像度を大きいものから小さいものに変更し、ウィンドウが収まらなくなったらサイズを変更することでできます。
と思うかもしれませんが、たかが
resize
(そしておそらく、さらにいくつかのような
scroll
スクリプトがスレッド化されているため、ユーザーがブラウザとアクティブなインタラクションをとっていないときに実行される可能性があります。そして、シングルウィンドウの場合は、あなたの言うとおりかもしれません。しかし、クロスウィンドウのスクリプトを実行すると、すべてが台無しになります。Safari 以外のブラウザでは、ウィンドウ、タブ、フレームがビジー状態のときにすべてブロックされるので、別のドキュメントのコードからドキュメントを操作することができ、別のスレッドで実行されて関連するイベント ハンドラを起動させることができます。
スクリプトがスレッド化されている間に、発生させることができるイベントを発生させることができる場所。
-
モーダルポップアップのとき (
alert
,confirm
,prompt
) は、Opera以外のすべてのブラウザで、開いています。 -
期間中
showModalDialog
をサポートするブラウザで利用できます。 -
このページのスクリプトはビジー状態かもしれません...」というダイアログボックスが表示され、スクリプトの実行を継続するように選択しても、Operaを除いて、ビジーループの最中でもリサイズやブラーなどのイベントが発生し処理されるようになりました。
-
以前、Sun Java Plugin を使用した IE で、アプレット上の任意のメソッドを呼び出すと、イベントが発生し、スクリプトが再入力されることがありました。これは常にタイミングに依存するバグで、Sunがその後修正した可能性があります(私は確かにそう願っています)。
-
おそらくもっと。私がこれをテストしてからしばらく経ちますが、ブラウザはその後複雑さを増しています。
要約すると、JavaScriptはほとんどのユーザーにとって、ほとんどの場合、厳密なイベント駆動型のシングルスレッドで実行されているように見えるのです。しかし、実際にはそのようなことはありません。どこまでが単なるバグでどこからが意図的な設計なのかは不明ですが、複雑なアプリケーション、特にクロスウィンドウ/フレームスクリプトのアプリケーションを書いている場合は、この問題が断続的に、しかもデバッグしにくい形であなたを苦しめる可能性は十分にあります。
最悪の場合、すべてのイベントレスポンスを間接化することで、並行処理の問題を解決することができます。イベントが来たら、それをキューに落とし、後で順番にキューを処理するために
setInterval
関数を使用します。もしあなたが複雑なアプリケーションで使われることを想定してフレームワークを書いているのであれば、これを行うことは良い手かもしれません。
postMessage
は、将来的にはクロスドキュメント・スクリプティングの痛みを和らげてくれることも期待しています。
関連
-
[解決済み】TypeError: Router.use() はミドルウェアの関数を要求しているが、Object を取得した。
-
[解決済み】「.addEventListener is not a function」なぜこのエラーが発生するのか?
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み] HTML5のlocalStorageにオブジェクトを格納する方法は?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JavaScriptのクロージャの説明
-
vueのグローバルがscss(mixin)を導入。
-
Vueのクラススタイルの使い方の詳細
-
Vueの「データを聴く」原則を解説
-
[解決済み】Uncaught SyntaxError: JSONの位置0に予期しないトークンuがあります。
-
[解決済み】GETできない / Nodejsエラー
-
[解決済み】React Nativeアプリをターミナルから実行するとエラーが発生する(iOS)
-
nodejs unhandledPromiseRejectionWarning メッセージ
-
[解決済み] JavaScriptプログラマーが知っておくべきこととは?[クローズド]
-
[解決済み】JavaScriptが同期であるのはいつ?