非同期処理入門ガイド
はじめに
JavaScriptはシングルスレッドで動いているため、時間のかかる処理をそのまま書くと画面が固まってしまいます。
そこで使われるのが非同期処理です。非同期処理を理解すると、API通信やタイマー処理などをスムーズに扱えるようになります。
シングルスレッドとは
特徴
- 同時に複数の処理を並行して実行できない
- 1つの処理が長時間止まると、他の処理も待たされてしまう
- 例:重い計算を同期的に書くと、画面が固まってユーザー操作を受け付けなくなる
解決策
- 非同期処理を使って「待ち時間がある処理」を後回しにし、他の処理を先に進める
- これにより、ユーザー体験がスムーズになる
👉 シングルスレッドだからこそ、非同期処理は必須の仕組みなのです
1. コールバック関数
処理が終わったら呼び出す関数を渡す方法です。
console.log("処理開始");
setTimeout(() => {
console.log("3秒後に実行されました");
}, 3000);
console.log("処理は続行しています");
ポイント
- setTimeout や setInterval は代表的な非同期処理
- 処理が終わったら「コールバック関数」が呼ばれる
- シンプルだが、入れ子が深くなる「コールバック地獄」に注意
コールバック地獄とは
非同期処理を「コールバック関数」だけで書くと、入れ子がどんどん深くなってしまう問題のこと
doSomething(function(result1) {
doSomethingElse(result1, function(result2) {
doThirdThing(result2, function(result3) {
doFourthThing(result3, function(result4) {
console.log("完了:", result4);
});
});
});
});
問題点
- ネストが深くなり、コードが右にずれて読みにくい
- エラー処理が複雑になる
- 保守性が低く、バグが増えやすい
解決策
- Promise を使うと、.then() チェーンでフラットに書ける
- async/await を使うと、同期処理のように直線的に書ける
コールバック地獄を避けるために、JavaScriptでは async/await が推奨されています
2. Promise
非同期処理の結果を「成功(resolve)」か「失敗(reject)」で扱う仕組みです。
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("成功!"), 2000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error));
ポイント
- then で成功時の処理、catch で失敗時の処理を書く
- 複数の非同期処理を「チェーン」でつなげられる
- コールバックより読みやすいが、長くなると複雑になる
3. async / await
Promiseをより直感的に書ける構文です。同期処理のように書けるので読みやすいです。
async function fetchData() {
try {
let response = await fetch("https://api.example.com/data");
let data = await response.json();
console.log(data);
} catch (error) {
console.error("エラー:", error);
}
}
fetchData();
ポイント
- await は「Promiseの結果が返るまで待つ」
- try...catch でエラー処理を簡単に書ける
- 実際の開発では最もよく使われる書き方
4. タイマー処理
一定時間後や一定間隔で処理を実行できます。
// 3秒後に1回だけ実行
setTimeout(() => {
console.log("3秒後に表示");
}, 3000);
// 1秒ごとに繰り返し実行
let count = 0;
let timer = setInterval(() => {
count++;
console.log("回数: " + count);
if (count === 5) clearInterval(timer); // 5回で停止
}, 1000);
ポイント
- setTimeout → 一度だけ実行
- setInterval → 繰り返し実行
- clearTimeout / clearInterval で停止できる
5. Promise.all / Promise.race
複数の非同期処理をまとめて扱う方法です。
let p1 = new Promise(resolve => setTimeout(() => resolve("A完了"), 1000));
let p2 = new Promise(resolve => setTimeout(() => resolve("B完了"), 2000));
Promise.all([p1, p2]).then(results => console.log(results));
// ["A完了", "B完了"]
Promise.race([p1, p2]).then(result => console.log(result));
// "A完了"(先に終わったものだけ返す)
ポイント
- Promise.all → 全部終わるまで待つ
- Promise.race → 一番早く終わったものだけ返す
- 複数のAPI通信をまとめて扱うときに便利
6. 非同期処理が使われる場面
- API通信:サーバーからデータを取得
- ファイル読み込み:画像や動画のロード
- タイマー処理:一定時間後に処理を実行
- ユーザー操作:クリックや入力イベント
これらはすべて「待ち時間がある処理」なので、非同期で書く必要があります。
7. まとめ
この記事では、JavaScriptの非同期処理について紹介しました。
- コールバック関数:処理が終わったら呼び出す関数を渡す
- Promise:成功と失敗を分けて書ける仕組み
- async / await:同期処理のように書けて読みやすい
- タイマー処理:時間を指定して処理を実行
- Promise.all / Promise.race:複数の非同期処理をまとめて扱う
非同期処理を理解すると、API通信やユーザー操作をスムーズに扱えるようになります。