JavaScriptの非同期処理について
雑記事。暫定的な理解を書き連ねているので、誤った情報が含まれている可能性が多分にあります。
— kappaz@技術書典7 か02C (@kpinput) 2019年10月19日
こんな気持ちだったので、async/awaitに関して調べていたら、
そもそも非同期処理についてほぼ理解していないことに気づく。
「なんかよく分からないが、JavaScriptはデフォルトで非同期になることがある」 くらいにしか理解してなかった。それでよくこの半年あまりやってこれたなぁ。 (案外動かすだけならなんとかなる)
たどり着いたのが以下の記事。そもそもJavaScriptにおける非同期処理とはなんぞや? という点を解説してくれている。
その結果こんな感じになった。素晴らしい。
https://t.co/AY1vT4XakE
— kappaz@技術書典7 か02C (@kpinput) 2019年10月19日
この記事でJavaScriptの非同期処理を完全に理解したわ pic.twitter.com/CXQg0envOZ
学んだことを軽くまとめていく。なんとなくこのネタLTとかに使えそうだ。
そもそもJavaScriptには非同期関数という分類の関数が存在し、呼び出すと非同期に実行される
根本的にここを理解できていなかった。JavaScriptにおける同期・非同期は、実行する関数に依存している様子。
基本的に実行に時間がかかる処理が非同期関数になる様子ようだ。例えばsetTimeOut()やHTTPリクエストを行う関数などがそれに該当する。
teratail.com 上の記事では非同期関数に分類される関数に関して、以下のような分類が提案されている。参考になるかもしれない。
非同期関数を呼び出した後、具体的な処理はWebAPIに丸投げして、以降の関数を実行する
与えられた処理内容を外部のWebAPIにいわば投げてしまいます。外部WebAPIに「これをやってくれ!」と頼んだあとは、関数としては実行終了してしまい、コールスタックから取り除かれてJavaScriptインタプリタは次の関数の実行を進めていきます。 JavaScriptインタプリタがどんどん次の関数を実行している間にも、処理を任せられたWebAPIの方は独自に処理を実行し続けています。 (中略) このように、処理をWebAPIに任せる関数を使うことで「2つ以上の処理を同時に進め、処理が完了したタイミングで指定した処理を実行する」非同期処理が実現できます。JavaScriptはシングルスレッドなので、別のスレッドを立ててマルチスレッド的に並列処理をしているわけではなく、WebAPIさんという「他の人」に代わりに処理を実行してもらうことで擬似的に並行処理を行なっているのがわかるかと思います。
「JavaScriptはシングルスレッドだというのに、非同期処理を呼び出したとして一体誰が実行するんだ?」 という疑問を薄ぼんやりと持っていたが、 それにピンポイントで答えてくれたのがこれ。 「JavaScriptにおける非同期処理の実態が掴めて来た」と感じさせてくれた文章。大変感謝している。 ただしWebAPIとはなんぞや?というのをいまいち理解していないので要調査。 コールスタック等の解説は当該記事参照。
WebAPIの処理が完了した後は、JavaScript側に処理が戻る
WebAPIの処理が完了した後は、コールバックがタスクキューに突っ込まれる。 コールスタックが空になった時点でイベントループによってコールバックがタスクキューからコールスタックに突っ込まれる。
以下記事からの引用。
WebAPIの処理が完了した時、コールバック関数はタスクキューに追加されます。 コールスタックが空になった時、イベントループによってタスクキューに登録された関数が登録された順に取り出され、コールスタックの中に突っ込みまれます。 あとは通常通り関数が実行され、コールスタックから取り除かれる流れが始まります。 (中略) コールスタックの中身が空になりコードも全て読み終わったので、イベントループによってタスクキューの中のCB1(コールバック)がコールスタックに追加されます。
わかりやすい解説動画。ただし英語
上の記事を人通り読んだ上で見るととてもわかりやすい。
最後に
おそらくPromiseやasync/awaitもこの処理をより楽に実現するためのシンタックスシュガーの類でしかないと予想している。 これで学習が捗るといいなぁ。。。 あと今日の記事は本当に書きなぐり。自分用のブログだしこんなもんでいいか。 Twitterには展開できませんね。