[[ES2015]]より前の時代では、非同期処理の記述方法は[[コールバック関数 (JavaScript)|コールバック関数]]以外ありませんでした。2025年の今、その書き方をすることはほぼありませんが、現代の構文が必要な背景を知ることには価値があります。何より知らなければ昔のコードを読むこともできません。 ## Reference - [非同期処理:Promise/Async Function · JavaScript Primer \#jsprimer](https://jsprimer.net/basic/async/) ## Lesson [[コールバック関数 (JavaScript)|コールバック関数]]とは、『ある関数』に引数として渡され、『ある関数』の中で特定処理の発生前後に実行される関数のことです。 ``` // 『ある関数』の中で特定処理が発生する前後で実行される『コールバック関数』を引数に指定 function ある関数(callback) { // 何らかの処理 callback(); // コールバック関数を実行 } // 使用例 ある関数(() => { console.log("コールバック関数が実行されました"); }); ``` 代表的な[[コールバック関数 (JavaScript)|コールバック関数]]として[[setTimeout (JavaScript)|setTimeout]]があります。 ```js console.log("処理開始"); setTimeout(() => { console.log("2000ms(2秒)後に出力されるメッセージ"); }, 2 * 1000); console.log("setTimeoutのコールバック関数を待たずにここは実行される") ``` > [!hint] > 実際に[[コールバック関数 (JavaScript)|コールバック関数]]を使う必要のあるケースは、[[REST API]]の呼び出しやファイルの読み込み/書き込みなどが多いです。 ## Mission 1 #😁EASY 以下のソースコードを実行したときの出力内容を記載してください。 ```js console.log("A"); setTimeout(() => { console.log("B"); }, 2 * 1000); console.log("C"); ``` %% 解答例 ```js A C B ``` %% ## Mission 2 #🙂NORMAL 第1引数で指定した秒数後に、第2引数で指定した結果を出力するコードを書いてください。 ```js function delayConsoleLog(delaySec, output) { // FIXME: 実装 } ``` %% 解答例 ```js function delayConsoleLog(delaySec, output) { setTimeout(() => { console.log(output); }, delaySec * 1000); } ``` %% ## Mission 3 #🙂NORMAL [[#Mission 2]]で作成した関数を使って、以下の挙動となるコードを書いてください。 | 実行時を `00:00:00` としたときの時刻 | その時点で新たに出力される内容 | | ------------------------ | --------------- | | 00:00:01 | 1秒後に結果を表示 | | 00:00:02 | 2秒後に結果を表示 | | 00:00:03 | 3秒後に結果を表示 | %% 解答例 ```js delayConsoleLog(1, "1秒後に結果を表示"); delayConsoleLog(2, "2秒後に結果を表示"); delayConsoleLog(3, "3秒後に結果を表示"); ``` %% ## Mission 4 #🙂NORMAL 第1引数に[[コールバック関数 (JavaScript)|コールバック関数]]を受け、ランダムで3秒以内の時間が経過したら[[コールバック関数 (JavaScript)|コールバック関数]]が実行される関数 `randomDelay` を実装してください。 ```js function randomDelay(callback) { // FIXME: 実装 } ``` %% 解答例 ```js function randomDelay(callback) { setTimeout(callback, Math.random() * 3000); } ``` %% > [!hint]- Hint 1 > ランダムについては[[乱数を扱う (JavaScript)|乱数を扱う]]方法を参照。 ## Mission 5 #🙂NORMAL [[#Mission 4]]の関数をコメントのように実行したいとき、この実装では期待通り動かない理由を説明してください。 ```js randomDelay(() => { console.log("1") }) // ↑のconsole.log("1")が実行されてから実行したい randomDelay(() => { console.log("2") }) // ↑のconsole.log("2")が実行されてから実行したい randomDelay(() => { console.log("3") }) ``` %% 解答例 `randomDelay` は `setTimtout` が実行されれば次に進んでしまい、`console.log(...)` が呼びだされるまで待ってくれないから。 %% ## Mission 6 #🙂NORMAL [[#Mission 5]]のコードを要件を満たすように書き換えてください。 %% 解答例 ```js randomDelay(() => { console.log("1"); randomDelay(() => { console.log("2"); randomDelay(() => { console.log("3"); }); }); }); ``` %% > [!hint]- Hint 1 > `randomDelay` 完了後に処理を繋げたいなら、[[コールバック関数 (JavaScript)|コールバック関数]]を使うしかありません。 --- *NEXT* >> [[📗TDQ-024 Promiseの基本 正常系]]