「javascriptは非同期言語なので、時間のかかる処理は後回しになる」といった書き方をしている記事をいくつか目にしたことが有ります。僕も以前は「たぶん後回しになるんだろうな~」くらいに思っていました。
しかし、「時間のかかる処理は後回しになる」は、正しくない認識です。
非同期関数等を除けば、基本的には時間のかかる処理であっても同期処理(上から順に処理)されます。
以下のコードはそのー例です。
console.log("while前")
start = Date.now()
while(true){
if( Date.now() - start > 3000){
console.log("3秒経過");
break;
}
}
console.log("while後")
//"while前"
//"3秒経過"
//"while後"
上記コードを実際に実行するとコンソールには以下の順で表示されます。
・while前
・3秒経過
・while後
3秒もかかるwhileの処理を待ってから、console.log("while終了後")
が実行されていることがわかります。
もうひとつ似たような例を用意してみました。
console.log("for前")
for(let i = 0;i <= 10000; i++){
if(i == 10000){console.log("10000")};
}
console.log("for後")
//"for前"
//"10000"
//"for後"
こちらも同様で、コンソールに表示される順番は「for前」→「10000」→「for後」となります。
つまり、時間のかかる処理でも後回しにせずに同期的に(上から順に)処理していることがわかります。
setTimeout等が特殊なだけ
setTimeoutを使用して上記2つのコードと似たようなことを行ってみます。
console.log("setTimeout前")
setTimeout(function(){
console.log("3秒経過")
},3000)
console.log("setTimeout後")
//"setTimeout前"
//"setTimeout後"
//"3秒経過"
この場合、コンソールに表示される順番は「setTimeout前」→「setTimeout後」→「3秒経過」となり
setiTimeoutの処理を待たずにconsole.log("setTimeout後")
が実行されていることがわかります。
そして、こうなる理由は「時間のかかる処理を後回しにしているから」ではなく「setTimeoutのような非同期処理をする関数を使用しているから」です。
その裏付けとなるのが以下のコードとなります。
setTimeout(function(){
console.log("setTimeout終了")
},0)
start = Date.now()
while(true){
if( Date.now() - start > 3000){
console.log("while終了");
break;
}
}
//"while終了"
//"setTimeout終了"
コードを見てもわかるとおり、whileの処理には3秒かかるのに対し、setTimeoutは0秒に設定してあります。
もし「時間のかかる処理が後回しになる」のであればコンソールの表示順はsetTimeout終了
→while終了
となるはずですが、
実際に実行するとwhile終了
→setTimeout終了
となります。
これは、非同期関数に渡されたコールバック関数は同期処理の後に実行される、という処理順序があるからです。
↓そのあたりわかりやすく解説してくださっている記事
https://qiita.com/UTDoi/items/d49ea919818d9b519f93
まとめ
「時間のかかる処理」が後回しになるのではなく、非同期関数に渡されたコールバック関数の処理が後回しになる。
JavaScriptは非同期言語?
これに関しては、非同期言語の定義がはっきりしないので何とも言えません。
ただ、JavaScript自体はシングルスレッドの言語であり、上に書かせて頂いる内容なども含めて考えると
非同期言語と断定できるものではないような気がします。