JavaScriptはシングルスレッドであることが知られています。そして、Promiseを用いた非同期処理ができることは周知の事実です。では、なぜシングルスレッドで非同期処理ができるのでしょうか? その点について、非同期処理のための2種類のQueuesについて触れつつ、コードベースでの説明も行います。
JavaScriptはなぜシングルスレッドでも非同期処理ができるのかお昼のLT2021/09/07Takashi Mima(@task4233)
View Slide
本LTの目標・JavaScript(ECMAScript)がシングルスレッドで非同期処理を 実現している方法をざっくり理解すること本LTの想定対象者・JavaScriptの基本的な文法を理解している人・シングルスレッドの概念を理解している人本LTの非想定対象者・内部実装にあまり興味がない人・JavaScriptを全く触れたことがない人2
TL;DR(ECMAScript)JavaScriptはシングルスレッド・Event LoopとCall Stackを用いて動いている非同期処理を実現するための2種類のQueue・Micro Task Queue・Macro Task Queue処理の優先度・Call Stack > Micro Task Queue > Macro Task Queue3
自己紹介・Takashi Mima(@task4233)・芝浦工業大学 M1・サーバサイドとセキュリティ・散歩とGoが好き4
JavaScript(以下JS)の変遷1995 LiveScriptの誕生(後のJS)1995 JScriptの登場(当時のJSと互換性ナシ)1997 ECMAに標準化を依頼(いわゆるECMAScript)2000~ 第3版派と第4版派の軋轢(低迷)2005~ Ajax, prototype.js, jQuery等の登場(持ち直し)2008 V8エンジンの登場(JITコンパイルによる高速化)2009 Node.jsの登場(モジュール管理が可能に)……5
非同期処理に欠かせないPromiseオブジェクトState(状態)とValue(値)を持つ・Stateはfulfilled✅ /rejected❌ /pending⏳ の3種類・Valueは結果Promise(resolve func, reject func)で生成・fulfilled✅ => resolve funcを実行・rejected❌ => reject funcを実行状態を持てるので、非同期処理に用いられる6
JavaScriptはシングルスレッドシングルスレッド・1度に1つのタスクしか実行できない・メモリ空間での競合が起きないEvent Loopに従ってタスクを処理する・タスクを処理する無限ループ・DOMの更新もタスクの1つ処理はCall Stackで実行される・処理のためのStack・処理を実行するWEB APIにデータを流す・Pushed -> Invoke -> Pop(& return Value)の順に7
シングルスレッド?8
あるタスクの実行中には非同期処理を動かせないはず(シングルスレッドなので)9
Q. どうやって非同期処理してるの?🤔10
A. Queueを別に持つことで非同期っぽく逐次処理している11
2種類のQueuesMicro Task Queue・優先度の高い方のQueue・process.nextTick, Promise callbackなどMacro Task Queue・優先度が低い方のQueue・setTimeout, setInterval, setImmediateなど処理の優先度・Call Stack > Micro Task Queue > Macro Task Queue非同期処理に用いられる12
コードベースで考えてみるCall StackMicro TaskQueueMacro TaskQueueEvent LoopLog:13
Log:コードベースで考えてみるCall StackMicro TaskQueueMacro TaskQueueEvent Loop14
Log:コードベースで考えてみるconsole.log(‘Start’);Micro TaskQueueMacro TaskQueueEvent Loop15
コードベースで考えてみるCall StackMicro TaskQueueMacro TaskQueueEvent LoopLog: Start16
コードベースで考えてみるCall StackMicro TaskQueue() => {console.log(‘timeout’)}Event LoopLog: Start17
コードベースで考えてみるCall StackMicro TaskQueue() => {console.log(‘timeout’)}Event LoopLog: Start18
コードベースで考えてみるCall Stack(res) => {console.log(res);}() => {console.log(‘timeout’)}Event LoopLog: Start19
コードベースで考えてみるCall Stack(res) => {console.log(res);}() => {console.log(‘timeout’)}Event LoopLog: Start20
コードベースで考えてみるconsole.log(‘End’);(res) => {console.log(res);}() => {console.log(‘timeout’)}Event LoopLog: Start21
コードベースで考えてみるCall Stack(res) => {console.log(res);}() => {console.log(‘timeout’)}Event LoopLog: Start End22
コードベースで考えてみるCall Stack(res) => {console.log(res);}() => {console.log(‘timeout’)}Event LoopLog: Start End23
コードベースで考えてみる (res) => {console.log(res);}Micro TaskQueue() => {console.log(‘timeout’)}Event LoopLog: Start End24
コードベースで考えてみるCall StackMicro TaskQueue() => {console.log(‘timeout’)}Event LoopLog: Start End promise25
コードベースで考えてみる () => {console.log(‘timeout’)}Micro TaskQueueMacro TaskQueueEvent LoopLog: Start End promise26
コードベースで考えてみるCall StackMicro TaskQueueMacro TaskQueueEvent LoopLog: Start End promise timeout27
まとめJavaScriptはシングルスレッド・Event LoopとCall Stackを用いて動いている非同期処理を実現するための2種類のQueue・Micro Task Queue・Macro Task Queue処理の優先度・Call Stack > Micro Task Queue > Macro Task Queueありがとうございました! 28
参考資料・✨♻ JavaScript Visualized: Event Loop - DEV Community・⭐🎀 JavaScript Visualized: Promises & Async/Await - DEV Community・Understanding the node.js event loop・voyagegroup/treasure-javascript-2020: Treasure Frontend 講義資料とか・ そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する29