$30 off During Our Annual Pro Sale. View Details »

JavaScriptはなぜシングルスレッドでも非同期処理ができるのか/Why Can JavaSctipt Invoke Asynchronous in Single Thread?

task4233
September 07, 2021

JavaScriptはなぜシングルスレッドでも非同期処理ができるのか/Why Can JavaSctipt Invoke Asynchronous in Single Thread?

JavaScriptはシングルスレッドであることが知られています。そして、Promiseを用いた非同期処理ができることは周知の事実です。では、なぜシングルスレッドで非同期処理ができるのでしょうか?
その点について、非同期処理のための2種類のQueuesについて触れつつ、コードベースでの説明も行います。

task4233

September 07, 2021
Tweet

More Decks by task4233

Other Decks in Technology

Transcript

  1. JavaScriptは
    なぜシングルスレッドでも
    非同期処理ができるのか
    お昼のLT
    2021/09/07
    Takashi Mima(@task4233)

    View Slide

  2. 本LTの目標
    ・JavaScript(ECMAScript)がシングルスレッドで非同期処理を
     実現している方法をざっくり理解すること
    本LTの想定対象者
    ・JavaScriptの基本的な文法を理解している人
    ・シングルスレッドの概念を理解している人
    本LTの非想定対象者
    ・内部実装にあまり興味がない人
    ・JavaScriptを全く触れたことがない人
    2

    View Slide

  3. TL;DR(ECMAScript)
    JavaScriptはシングルスレッド
    ・Event LoopとCall Stackを用いて動いている
    非同期処理を実現するための2種類のQueue
    ・Micro Task Queue
    ・Macro Task Queue
    処理の優先度
    ・Call Stack > Micro Task Queue > Macro Task Queue
    3

    View Slide

  4. 自己紹介
    ・Takashi Mima(@task4233)
    ・芝浦工業大学 M1
    ・サーバサイドとセキュリティ
    ・散歩とGoが好き
    4

    View Slide

  5. 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

    View Slide

  6. 非同期処理に欠かせないPromiseオブジェクト
    State(状態)とValue(値)を持つ
    ・Stateはfulfilled✅ /rejected❌ /pending⏳ の3種類
    ・Valueは結果
    Promise(resolve func, reject func)で生成
    ・fulfilled✅ => resolve funcを実行
    ・rejected❌ => reject funcを実行
    状態を持てるので、非同期処理に用いられる
    6

    View Slide

  7. JavaScriptはシングルスレッド
    シングルスレッド
    ・1度に1つのタスクしか実行できない
    ・メモリ空間での競合が起きない
    Event Loopに従ってタスクを処理する
    ・タスクを処理する無限ループ
    ・DOMの更新もタスクの1つ
    処理はCall Stackで実行される
    ・処理のためのStack
    ・処理を実行するWEB APIにデータを流す
    ・Pushed -> Invoke -> Pop(& return Value)の順に
    7

    View Slide

  8. シングルスレッド?
    8

    View Slide

  9. あるタスクの実行中には
    非同期処理を動かせないはず
    (シングルスレッドなので)
    9

    View Slide

  10. Q. どうやって非同期処理してるの?
    🤔
    10

    View Slide

  11. A. Queueを別に持つことで
    非同期っぽく逐次処理している
    11

    View Slide

  12. 2種類のQueues
    Micro Task Queue
    ・優先度の高い方のQueue
    ・process.nextTick, Promise callbackなど
    Macro Task Queue
    ・優先度が低い方のQueue
    ・setTimeout, setInterval, setImmediateなど
    処理の優先度
    ・Call Stack > Micro Task Queue > Macro Task Queue
    非同期処理に
    用いられる
    12

    View Slide

  13. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    Log:
    13

    View Slide

  14. Log:
    コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    14

    View Slide

  15. Log:
    コードベースで考えてみる
    console.log(‘Start’);
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    15

    View Slide

  16. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    Log: Start
    16

    View Slide

  17. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
    17

    View Slide

  18. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
    18

    View Slide

  19. コードベースで考えてみる
    Call Stack
    (res) => {
    console.log(res);
    }
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
    19

    View Slide

  20. コードベースで考えてみる
    Call Stack
    (res) => {
    console.log(res);
    }
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
    20

    View Slide

  21. コードベースで考えてみる
    console.log(‘End’);
    (res) => {
    console.log(res);
    }
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
    21

    View Slide

  22. コードベースで考えてみる
    Call Stack
    (res) => {
    console.log(res);
    }
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
       End
    22

    View Slide

  23. コードベースで考えてみる
    Call Stack
    (res) => {
    console.log(res);
    }
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
       End
    23

    View Slide

  24. コードベースで考えてみる (res) => {
    console.log(res);
    }
    Micro Task
    Queue
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
       End
    24

    View Slide

  25. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    () => {
    console.log(‘timeout’)
    }
    Event Loop
    Log: Start
       End
       promise
    25

    View Slide

  26. コードベースで考えてみる () => {
    console.log(‘timeout’)
    }
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    Log: Start
       End
       promise
    26

    View Slide

  27. コードベースで考えてみる
    Call Stack
    Micro Task
    Queue
    Macro Task
    Queue
    Event Loop
    Log: Start
       End
       promise
       timeout
    27

    View Slide

  28. まとめ
    JavaScriptはシングルスレッド
    ・Event LoopとCall Stackを用いて動いている
    非同期処理を実現するための2種類のQueue
    ・Micro Task Queue
    ・Macro Task Queue
    処理の優先度
    ・Call Stack > Micro Task Queue > Macro Task Queue
    ありがとうございました! 28

    View Slide

  29. 参考資料
    ・✨♻ 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

    View Slide