なぜシングルスレッドで非同期実行できるのか?(Javascript)

default eye catch プログラミング

javascriptの非同期実行について、そもそもシングルスレッドなのにどうやって実現しているんだ?というところが気になったので調べてみました。


javascriptはシングルスレッドで実行されます。
つまり、複数の処理を並行に進めることができないということです。

一方、javascriptは非同期実行の仕組みを持っています。

ES2015で追加されたPromiseや、ES2017で定義されたasync/awaitなどです。

本来シングルスレッドでしか実行できない言語が、どうして非同期実行(つまり並行的な処理)ができるのでしょうか?

ポイントは

javascriptの処理とブラウザAPIの処理の違いを区別する

ということです。

Some Javascript features are actually Browser APIs - Dillion's Blog
JavaScript uses browser APIs to perform some operations on the web. Without these APIs, Javascript cannot do what many p...

こちらの記事が非常にわかりやすく、ストンと腑に落ちました。

javascriptによるプログラム実行は、ざっくり大別すると
・javascriptエンジンによる処理
・ブラウザAPIによる処理
に分かれます。

そしてよく使うsetTimeoutや、documentオブジェクトを使ったDOMの処理関連などは、実はすべてブラウザAPIが提供する機能です。

ブラウザAPIによる処理自体に、javascriptエンジンは関与しません。
つまりjavascriptエンジン内で、複数の処理を並行処理することはできませんが、javascriptエンジンによる処理とブラウザAPIによる処理が並行で進行することは可能となります。

非同期的なjavascript実行では、javascriptエンジンが上記のようなブラウザAPIを利用した処理を委任し、その間に他の処理を実行している、ということになります。

これが、JavaScriptがシングルスレッドでありながら、非同期実行を可能にしている理由です。

そして私たちが普段使うような主要なブラウザは、基本的にW3Cが標準化している仕様に則って作られています。

そのため、ブラウザが違うことでブラウザAPIが異なり、同じjavascriptのコードで違う挙動をする、といった事故も起こりづらくなっているわけですね。

W3C
The World Wide Web Consortium (W3C) develops standards and guidelines to help everyone build a web based on the principl...

それでは、例えばnode.jsなど、ブラウザを介さないjavascirptエンジンを使ったフレームワークではブラウザAPIが実装されていないのにsetTimeout諸々を使ったり、非同期処理を行ったりできるの?というところが気になりますよね。

node.jsでは、こうしたブラウザAPIが提供する機能を自前で提供しています。そのため、ブラウザと同じような環境でユーザーはjavascriptを動かすことができるということです。


まとめ

・javascriptはシングルスレッドのため、本来javascriptエンジンは並行処理ができない
・しかしブラウザAPIに処理を委任している間に、他の処理を行うことができる
・このような動きをしているのが、いわゆるjavascirptの非同期実行である

※非同期実行をより詳しく説明すると、インベントループやタスクキューといった仕組みも出てくるのですが、複雑で奥深い話題なのでここでは割愛します。

コメント

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