[JavaScript]非同期で重い処理を行うとブラウザは固まらない…というわけではないという話

昨日今日と、『ステップアップJavaScript フロントエンド開発の初級から中級へ進むために』という本を読んでいました。

タイトルにあるとおり、フロントエンド開発(というよりもJavaScriptの知識)について、初級から中級にステップアップするための本で、仕事として使うなら知っておきたい知識について詳しく書かれてありました。個人的には目新しいことはなかったですが、これからJavaScriptについて学んでいきたいと思われる方にはオススメです。

ただ、ちょっと気になったのが非同期処理についての説明。「何か行う度に無反応になってしまうシステムは使いづらいので、非同期を利用して快適に動作するように作ります。」と書かれてあり、その説明として載せている図が並列処理のよう。
その後のサンプルコードとして書かれてあるのが、fetchを使ったAjaxなので、間違ってはいない。ただ、中にはasyncを定義した非同期関数の中で重い処理を行っても、ブラウザは固まらないのではないと思いそうな記述だと思ったけど、実際はそうではない。

それを説明するために以下で、簡単なサンプルを提示します。

See the Pen
非同期で重い処理
by amano225 (@amano225)
on CodePen.


(なお、CodePenでは時間のかかるループ処理を行うと、途中でループを強制的に抜けてしまうのですが、「window.CP.PenTimer.MAX_TIME_IN_LOOP_WO_EXIT = 20000;」と記述することで、20秒間はループを止めないようにしています。参考:You Can Adjust The Infinite Loop Protection Timing – CodePen Blog)

このコードは、「非同期で重い処理」ボタンを押すと「heavyProc」という関数を非同期で呼び出し、その中で10秒間ずっとループ処理を行う処理を行っています。また、関数の最初と最後には、console.logで時間を出力しており、どのタイミングで実行されたかが分かるようになっています。
「単純処理」ボタンを押した時には、ただたんにconsole.logで時間を出力します(実は今回のサンプルを作るまで、関数にasyncキーワードをつけたら非同期で呼ばれるものかと思っていたのだけど、どうやらawaitを使わないと非同期にならないらしい)。

ここで、「非同期で重い処理」ボタンを押してから、「単純処理」ボタンを10回押したら下記のようにログが出力されました。

「end clickHeavy」より、「start heavyProc」のほうが後に出力されているので、非同期で実行されているのが分かります。ただ、単純処理を押したログの「clickSimple」は「end heavyProc」のログが出力されてから実行されています。もちろん、10秒処理が終わってからクリックしたわけではないです(そもそも、ミリ秒単位で全く同じ時間に2回クリックなんてできないしね)。

なぜこうなるかというと、JavaScriptは基本的にシングルスレッドなので、非同期関数の中で重い処理を行っても、ブラウザは固まってしまうわけです。
なお、「基本的に」と書いたのは、Web Workerという仕組みを使う事で、並列実行することができます。ただ、自分もWeb Workerはなんとなく知ってるだけで、ほとんど使ったことはないです。
今回紹介した本にも、Web Workerについては触れられていなかったのですが、JavaScriptはシングルスレッドだということは書いてほしかったなと思いました(それを書くと話がややこしくなるかもしれないけど)。

ステップアップJavaScript フロントエンド開発の初級から中級へ進むために
サークルアラウンド株式会社(著), 佐藤 正志(著), 小笠原 寛(著)
翔泳社 (2022-01-14T00:00:01Z)
5つ星のうち4.7

コメント

タイトルとURLをコピーしました