PHP8.1で非同期処理が書ける様になったので、JavaScriptの非同期処理について、スタック、キュー、イベントループなどの言葉を使わないで説明します。
// 素数を割り算で求める計算だけをする実行に時間のかかる関数
function sleep(){
for(let i= 2; i<100000; i++){
for(let j = i - 1; j > 1; j--){
if(i % j === 0){
break;
}
}
}
console.log('おしまい');
}
// 0.1秒後, 0.2秒後に表示されるのを期待している
setTimeout(()=>{console.log('setTimeout!200')}, 200);
setTimeout(()=>{console.log('setTimeout!100')}, 100);
sleep();
上記コード実行するとマシンのパワーにもよりますが5秒くらいたってから
setTimeout!100
setTimeout!200
と表示されます。0.1秒後と0.2秒後に表示したかったのに・・・。
登場人物は「ブラウザ」、「JSを実行する場所」、「順番待ち列」
setTimeoutはブラウザの役割です。これがポイントです。
JSの関数の実行順序は以下の通り。
- JavaScriptのコードは書かれている順に順次「JSを実行する場所」で実行されていく。
- 順次実行するコードにsetTimeoutがあったら、setTimeoutの中の関数を実行しないで「ブラウザ」に渡す。
- ブラウザは指定された時間になったら「順番待ち列」に受け取った関数を入れる。
- 「JSを実行する場所」は引き続きコードを実行していっている。実行するコードがなくなったら、関数は「順番待ち列」から「JSを実行する場所」へ入ることができる。
- 「JSを実行する場所」で関数が実行される。
上の方で書いたプログラムだと、ブラウザはsetTimeoutで渡された関数を100ms, 200ms後に「順番待ち列」に入れたんだけど、その関数たちはsleep();
が終わるまでを「JSを実行する場所」に入れなかったという事です。
setTimeoutはブラウザの役割と書きましたが、例えば、ボタンをクリックしたときに関数を「順番待ち列」に入れるのもブラウザの役割です。