[[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の基本 正常系]]