Upgrade to Pro — share decks privately, control downloads, hide ads and more …

おっさんでもわかる Javascriptのナゾ仕様

Guarneri009
June 01, 2023
770

おっさんでもわかる Javascriptのナゾ仕様

Guarneri009

June 01, 2023
Tweet

Transcript

  1. ©Project PLATEAU / MLIT Japan 高見英和 自己紹介 Takami Hidekazu • 兵庫県生まれ、20年以上前に札幌に移住

    • 医療関連企業で薬剤割付システムや創薬シス テムを開発していたがMierune MeetUpを みて転職 • 夏季はロードバイクで走りまくっていて、冬季 もZWIFT(室内サイクリング)でローラーを回 してます • 超レイトスターターのバイオリン弾き 5
  2. ©Project PLATEAU / MLIT Japan 言語別 非同期処理の違い ⚫ C/C++ ◦

    非同期といえばスレッド作成して処理をぶん投げる ◦ 同期したい場合はセマフォやミューテックスなどを使う 10
  3. ©Project PLATEAU / MLIT Japan 言語別 非同期処理の違い ⚫ C/C++ ◦

    非同期といえばスレッド作成して処理をぶん投げる ◦ 同期したい場合はセマフォやミューテックスなどを使う ⚫ Javascript ◦ async/await 11
  4. ©Project PLATEAU / MLIT Japan C/C++で非同期処理を書いてみる (がんばってモダンC++14) #include <iostream> #include <thread>

    constexpr int TIME_TO_SLEEP1 = 500; constexpr int TIME_TO_SLEEP2 = 1000; auto async_func() { for (auto i = 0; i < 10; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(TIME_TO_SLEEP1)); std::cout << "非同期処理 c++ async_func" << i << std::endl; } return 0; } int main(int argc, char const *argv[]) { std::cout << "==== start ====" << std::endl; auto work_thread = std::thread([]{ async_func(); }); for (auto i = 0; i < 5; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(TIME_TO_SLEEP2)); std::cout << "非同期処理 c++ mainFunc" << i << std::endl; } work_thread.join(); return 0; } 13
  5. ©Project PLATEAU / MLIT Japan Javascriptで非同期処理を書いてみる  // ビジーwaitを使う方法 function sleep(waitMsec)

    { var startMsec = new Date(); // 指定ミリ秒間だけループさせる(CPUは常にビジー状態) while (new Date() - startMsec < waitMsec); } function async_func() { setTimeout(() => { for (let i = 0; i < 10; ++i) { sleep(500) console.log(`非同期処理 javascript async_func ${i}`); } }, 0) } function main() { console.log(`==== start ====`); async_func(); for (let i = 0; i < 5; ++i) { sleep(1000) console.log(`非同期処理 javascript main ${i}`); } } main(); 14
  6. ©Project PLATEAU / MLIT Japan そもそも非同期処理の考え方が違うのでは ◦ C/C++  ▪ スレッドを並列させて処理速度を上げる

    ▪ 同時並行で処理させる(ソケット通信とか、WEBサーバーとか) ◦ Javascript ▪ シングルスレッドだけど処理中のブロックを避けたい (ノンブロッキング) 18
  7. ©Project PLATEAU / MLIT Japan Javascript非同期処理 今昔物語 非同期処理を書くには3つのパターンがある。 1. コールバック関数を連ねる。 俗

    にいう、コールバック 地 獄 に 陥 る 2. Promiseができたので  Promise  then thenで繋げる ECMAScript(ES2015 / ES6) 3. async await ができたのでスッキリ書ける。 ECMAScript(ES2017 / ES8) 19
  8. ©Project PLATEAU / MLIT Japan 以下のコードを実行すると、どの順番でメッセージが表示される? function a0() { console.log("Mierune")

    } setTimeout(function a1() { console.log("です。") }, 10); a0(); Promise.resolve() .then(function b1() { console.log("一緒に") }) .then(function b2() { console.log("仲間を") }); setTimeout(function a2() { console.log("募集中") }, 0); Promise.resolve() .then(function c1() { console.log("働いてくれる") }) .then(function c2() { console.log("絶賛") }); console.log("では") 22
  9. ©Project PLATEAU / MLIT Japan 理解するには  理解するには内部を理解する必要があった • コールスタック              後入れ先出し LIFO

    (Last-In-First-Out) • タスクキュー(マクロタスクキュー) 先入れ先出し FIFO (First-In-First-Out) • マイクロタスクキュー          先入れ先出し FIFO (First-In-First-Out) • イベントループ 優先順位は以下 • コールスタック=>実行 • マイクロタスクキュー (コールスタックが空の場合)=>コールスタック=>実行 • タスクキュー(コールスタックが空の場合)=>コールスタック=>実行   setTimeout関数などは指定した時間が経過したらコールバック関数をタスクキューに入れる  Promiseのコールバック関数は即座にマイクロタスクキューに関数を入れる 23
  10. ©Project PLATEAU / MLIT Japan まとめ 非同期を理解するには 26 1. シングルスレッドであること

    2. Promiseコールバック 関 数 、async 関 数 はマイクロスタックキューに 積 まれ 優 先 的 に 処 理 される。 3. set(Timeout,interbal,Immediate) 関 数 はタスクキューに 積 まれ マイクロスタックキューが空になってから処理される。 4. 可 視 化 ツールでためしてみる (https://www.jsv9000.app/)
  11. ©Project PLATEAU / MLIT Japan Pythonで非同期処理を書いてみる  MieruneではPythonを利用してバックエンド処理をすることが多い 28 import threading

    import time def async_func(): for i in range(10): time.sleep(0.5) print(f"非同期処理 python async_func {i}") def main(): print("==== start ====") work_thread = threading.Thread(target=async_func) work_thread.start() for i in range(5): time.sleep(1) print(f"非同期処理 python main_func {i}") work_thread.join() main() import asyncio import time import warnings warnings.filterwarnings('ignore') async def async_func(): asyncio.sleep(0) for i in range(10): time.sleep(0.5) print(f"非同期処理 python single async_func {i}") async def main(): print("==== start ====") async_task = asyncio.create_task(async_func()) for i in range(5): time.sleep(1) print(f"非同期処理 python single main_func {i}") asyncio.run(main()) スレッドを利用(マルチスレッド) asyncを利用(シングルスレッド)