Webサイトは、もう「ただ開いて読むだけ」の時代ではありません。
ボタンを押すと最新ニュースが読み込まれる、ページ遷移なしでエラーメッセージが表示される、位置情報や天気をサッと取ってきて画面に出す──。
こういった”止まらないUI”はすべて「非同期処理」という仕組みで動いています。
この記事では、はじめての人でもついていけるように、
- 同期処理ってなに?
- 非同期処理ってなに?
- Promiseは何をしてくれるの?
- async / await がなぜ読みやすいの?
- そして実戦編:Fetch APIでサーバーからデータ(JSON)をもらう
まで一気に整理していきます。
「難しそう…」って感じていても大丈夫。
順番に読めば「なんで必要なのか」「どこで使うのか」までちゃんとイメージできるようにしていきます。
目次
1. 同期処理(synchronous)とは?まずはここから
同期処理とは、「上から順番に、1つずつ終わらせてから次に進む」やり方のことです。
イメージでいうと、コンロが1口しかないキッチンで料理している状態です。
- まずソースを作る
- ソースが終わるまでハンバーグを焼けない
- ソースが完成してから、ようやくハンバーグを焼く
- 最後にソースをかけて完成
同時に複数のことはできないから、常に「待ち」が発生しますよね。これが同期処理です。
プログラム的に言うと:
- 今この行を実行中 → 終わるまで次の行には進まない
- 関数を呼び出した → その関数の処理が終わるまで、呼び出し元はいったんストップ
という流れになります。
同期処理のサンプルコード
function logTaskA() {
const now = new Date();
console.log(`TaskAスタート:${now.toLocaleString()}`);
}
function logTaskB() {
const now = new Date();
console.log(`TaskBスタート:${now.toLocaleString()}`);
}
// CPUをわざとつかませて「待たせる」処理
function busyBlock(waitMs) {
const begin = Date.now();
while (true) {
const elapsed = Date.now() - begin;
if (elapsed >= waitMs) {
return; // 指定ミリ秒経ったら抜ける
}
}
}
logTaskA(); // 1. まずAを実行
busyBlock(2000); // 2. 強制的に2秒ブロック
logTaskB(); // 3. 2秒後にBが実行される
流れはこうです:
logTaskA()がすぐ動くbusyBlock(2000)が2秒間ブロックして止める- 2秒経つまで
logTaskB()は実行されない
つまり「A→待つ→B」という順番が必ず守られます。これが同期処理。
2. 非同期処理(asynchronous)とは?「待ってる間に別のことする」
では非同期処理は何が違うのか。
コンロが2口あるキッチンを想像してください。
- コンロ1でソースを煮込みながら
- コンロ2で同時にハンバーグを焼ける
「ソースが終わるまで何もしない」じゃなくて、「待ってる間に別の仕事を進める」ことができます。
これが非同期処理のイメージです。
プログラム的に言うと:
- 「〇秒後にこれ動かしておいて」と予約だけして、すぐ次の処理に進む
- その”予約された処理”は、あとで別タイミングで実行される
- メインの流れは止まらない
なので、ユーザーは「画面が固まってる…」と感じにくくなります。UX(使いやすさ)が上がるんです。
3. 非同期処理の実例:setTimeout
JavaScriptには、すぐに使える代表的な非同期APIとして setTimeout があります。
setTimeout(コールバック関数, 待ち時間ミリ秒)
という形で使います。
「待ち時間ミリ秒が経ったら、このコールバック関数を呼んでね」という予約だけして、呼び出し元は止まらずに次に進みます。
同期版を非同期版に書き直す
さきほどの同期処理コードを、わざと非同期っぽく書き換えるとこうなります。
function logTaskA() {
const now = new Date();
console.log(`TaskAスタート:${now.toLocaleString()}`);
}
function logTaskB() {
const now = new Date();
console.log(`TaskBスタート:${now.toLocaleString()}`);
}
function logAsyncWork() {
const now = new Date();
console.log(`あとから実行された処理:${now.toLocaleString()}`);
}
logTaskA();
// 「2秒後にlogAsyncWorkを呼び出してね」と予約だけする
setTimeout(() => {
logAsyncWork();
}, 2000);
logTaskB();
これを実行すると、だいたいこんな順番になります。
TaskAスタート(すぐ出る)TaskBスタート(Aのすぐ後に出る)- 2秒たってから
あとから実行された処理
つまり、setTimeout の部分はすぐには実行されないんです。
「タイマーを仕込んでから、先にBを進める」という動きになる=非同期。
これが「待ってる間に別のことをする」という感覚です。
4. でも非同期はこれで終わらない:Promiseという考え方
setTimeout だけで済むうちはまだいいのですが、現実のWeb開発では「サーバーからデータを取ってくる」「通信が成功したらUIを更新する」「失敗したらエラーメッセージを出す」といったパターンが必須になります。
そこで登場するのが Promise(プロミス)です。
Promiseはなにを約束してくれる?
Promiseは「非同期の結果(成功 or 失敗)を、あとから教えてくれる箱」です。
- 成功したら →
resolve(...)を呼ぶ - 失敗したら →
reject(...)を呼ぶ - 呼び出し側は
.then(...)で成功時の処理を、.catch(...)で失敗時の処理を書ける
これによって、「いつ終わるかわからない処理」に対して、”終わった後に何をするか”をきれいに書けます。
Promiseの基本形
// 非同期で何かしたい処理をPromiseとして返す関数
function runAsyncDemo() {
return new Promise((ok, ng) => {
// ここに非同期の処理を書くイメージ
const isSuccess = false; // 成功と失敗を切り替えるテスト用フラグ
if (isSuccess) {
ok("非同期処理は成功しました!");
} else {
ng("非同期処理でエラーが発生しました。");
}
});
}
// Promiseを使う側
runAsyncDemo()
.then((msg) => {
console.log("成功時のメッセージ:", msg);
})
.catch((errMsg) => {
console.error("失敗時のメッセージ:", errMsg);
});
ここで大事なのは、
runAsyncDemo()を呼んだ瞬間に結果が返るわけじゃない.then(...)の中は「処理が終わったあと」に呼ばれる.catch(...)には失敗パターンがくる
ということです。
この「終わったあとでやることを登録しておく」という感覚がPromiseの世界観です。
5. Promiseを使って遅延処理を書く(setTimeout版のPromise化)
さっきの「2秒後に実行する処理」をPromise化してみると、もっとイメージしやすいです。
// ログ用の共通メッセージを返すだけの関数
function buildStartLog(label) {
const now = new Date();
return `${label} 開始時刻:${now.toLocaleString()}`;
}
// ただの処理A
function showTaskA() {
console.log(buildStartLog("処理A"));
}
// ただの処理B
function showTaskB() {
console.log(buildStartLog("処理B"));
}
// 2秒後にメッセージを返すPromise
function waitAndReport() {
return new Promise((done) => {
setTimeout(() => {
// 2秒後に完了扱いにして値を返す
done(buildStartLog("遅延タスク"));
}, 2000);
});
}
showTaskA();
// Promiseの完了後(then)にログを出す
waitAndReport().then((message) => {
console.log(message);
});
showTaskB();
この場合の実行イメージはこうです:
- 「処理A」ログが出る
- すぐ「処理B」ログも出る
- 約2秒後に「遅延タスク」のログが出る
waitAndReport() はすぐには結果を返さず、「あとで結果を渡すからね」というPromise(約束)を返しています。
呼び出し側は .then(...) の中に「結果が来たらやること」を書けばOK。
6. async / await:Promiseをもっと読みやすくする書き方
Promiseは便利なんですが、.then(...).then(...).then(...) とネストしていくと、だんだん読みにくくなることがあります。
そこで登場するのが async / await です。
asyncとは?
async function 関数名() { ... } のように async をつけた関数は、自動的にPromiseを返す関数になります。
awaitとは?
await は「このPromiseが解決(完了)するまで、この行でいったん待って。
終わったら結果ちょうだい」という意味になります。
ポイントは、
- awaitはasyncの中でしか使えない
- ソースコードが「同期っぽい読みやすさ」に近づく
ということです。
async/await
// 指定した秒数だけ待ってからメッセージを返すPromise関数
function pauseAndLog(sec) {
return new Promise((finish) => {
setTimeout(() => {
const now = new Date();
finish(
`pauseAndLogは${sec}秒待ってから実行されました:${now.toLocaleString()}`
);
}, sec * 1000);
});
}
// async関数:中でawaitが使える
async function runAsyncFlow() {
// pauseAndLogが完了するまで待って、戻り値をmsgに入れる
const msg = await pauseAndLog(3);
console.log(msg);
}
// 比較用の処理
function showAlpha() {
console.log("showAlpha: 実行開始");
}
function showBeta() {
console.log("showBeta: 実行開始");
}
// 実行してみる
showAlpha();
runAsyncFlow(); // ← ここで3秒待つが、全体は止まらない
showBeta();
実際の流れはこうなります。
showAlpha()がただちにログを出すrunAsyncFlow()が呼ばれるが、そこで3秒待つPromiseを仕込んでいる- 3秒経ったら
msgに文章が返ってきてconsole.log(msg)される
- 3秒経ったら
- しかしその待ち時間中も、
showBeta()がすぐ実行される
await のおかげで、then(...).catch(...) のような形ではなく、”いったん待って結果を受け取る” という自然な読み方ができます。
コードがスッキリしますよね。これが実務でとても重宝します。
7. JSONってなに?なぜみんなJSONでもらいたがるの?
非同期処理が本当に活きるのは「サーバーとデータをやり取りするとき」です。
ここでしょっちゅう登場するのが JSON(JavaScript Object Notation)。
JSONはざっくり言うと「JavaScriptのオブジェクトっぽい見た目をしたデータの表現ルール」です。
例:
{
"city": "Fukuoka",
"forecast": ["晴れ", "くもり", "雨"],
"publishedAt": "2025-10-29T09:00:00+09:00"
}
ポイントは、
{ ... }はオブジェクト[…]は配列"キー": 値のペアでデータが並んでいる- 文字列には基本ダブルクォーテーションを使う
JSONは軽くて読みやすいので、APIのレスポンス形式としていま標準的に使われています。
天気予報、ニュース、在庫情報、チャットのログ、フォームの送信結果など、なんでもJSONでもらうことが多いです。
8. Fetch APIでデータを取ってくる(非同期でサーバーにアクセス)
ではいよいよ実戦。
フロントエンド開発でよく使うのが Fetch API です。
Fetch API はブラウザに標準で入っている機能で、URLに対してHTTPリクエストを送り、返ってきたレスポンスをPromiseとして受け取ることができます。
fetch(どこに取りに行くか)- 返ってきたレスポンスを
.json()でJSONとして読み込む - その結果(オブジェクト)を好きに扱う
という流れです。
Fetch APIの基本的な書き方(Promiseスタイル)
// 天気データを配信しているAPIのURL(例)
const endpoint =
"https://www.jma.go.jp/bosai/forecast/data/forecast/400000.json";
fetch(endpoint)
.then((res) => {
// 受け取ったレスポンスをJSONとして解釈
return res.json();
})
.then((weatherData) => {
console.log("受け取った生データ:", weatherData);
// 特定エリアのデータを取り出す(例として最初のエリア)
const targetArea = weatherData[0].timeSeries[0].areas[0];
console.log("エリア情報:", targetArea);
console.log("エリア名:", targetArea.area.name);
console.log("今日の天気:", targetArea.weathers[0]);
console.log("明日の天気:", targetArea.weathers[1]);
console.log("あさっての天気:", targetArea.weathers[2]);
console.log("発表元:", weatherData[0].publishingOffice);
console.log("報告時刻:", weatherData[0].reportDatetime);
})
.catch((err) => {
console.error("天気データの取得に失敗しました。", err);
});
ここでやっていることは、
fetch(...)でサーバーに問い合わせ(非同期)- サーバーから返ってきたレスポンスを
.json()でオブジェクト化(これも非同期で、Promiseを返す) .then(...)の中で実際のデータを扱う.catch(...)でエラーハンドリング
です。
この取得したデータは、ただconsole.logするだけじゃなく、DOMを書き換えて画面に表示することもできます。
たとえば <div id="weatherBox"></div> にテキストを差し込む、といったことができます。
9. Fetch API × async/await版(より読みやすい書き方)
同じことは async/await でも書けます。
これはとても実戦的です。
async function loadWeather() {
const apiUrl =
"https://www.jma.go.jp/bosai/forecast/data/forecast/400000.json";
try {
// サーバーにアクセス(ここで結果が返るまで待つ)
const response = await fetch(apiUrl);
// レスポンスをJSONとして展開(これも待つ)
const info = await response.json();
console.log("取得した天気データ:", info);
// 特定エリアを取り出す(例として先頭エリア)
const regionData = info[0].timeSeries[0].areas[0];
console.log("地域名:", regionData.area.name);
console.log("きょう:", regionData.weathers[0]);
console.log("あした:", regionData.weathers[1]);
console.log("あさって:", regionData.weathers[2]);
// DOMに表示する例(画面に書き出す)
const box = document.getElementById("weatherBox");
if (box) {
box.textContent = `${regionData.area.name} の天気: ${regionData.weathers[0]}`;
}
} catch (e) {
console.error("天気情報の取得に失敗しました", e);
}
}
// 使い方
loadWeather();
この書き方だと、
await fetch(...):サーバーから返ってくるのを待つawait response.json():JSONパースが終わるのを待つ- その後は普通の変数として扱える
という流れで、同期処理っぽい読み心地になります。
「何がいつ完了するのか」「どこでエラーになるのか」が追いやすいので、メンテもしやすいです。
10. まとめ:なぜ非同期処理は避けて通れないのか
ここまでの話をまとめます。
- 同期処理
- 1つずつ順番に実行
- 前の処理が終わるまで次に進まない
- シンプルだけど、待ち時間が長いと画面が止まってしまう
- 非同期処理
- 「あとでやって」と予約して、すぐ次の処理に進める
- ユーザーにとって待ち時間のストレスが減る
- UIが止まらない・使いやすくなる
- Promise
- 非同期処理の「成功」「失敗」「結果の値」を表現する仕組み
.then(...)/.catch(...)で後続処理が書ける
- async / await
- Promiseをもっと読みやすく書くための文法
awaitで「Promiseが終わるまで一時停止して、結果を受け取る」が自然に書ける
- Fetch API
- JavaScriptからサーバーにアクセスしてデータを持ってくる標準的な方法
- 結果はJSONで受け取ることが多い
- 画面遷移なしで情報を更新できるから、UXが大きく向上する
あなたがこれを身につけると、「フォームを送信したときに、エラーをその場で出す」「天気予報やニュースを再読み込みなしで表示する」「APIから最新データを引っ張ってきてDOMを書き換える」といった、”いまのWebっぽい”ふるまいが自分で書けるようになります。
もう「静的なページのコーダー」ではなく、「インタラクションまで作れるフロントエンド」に一歩進んだ状態となります。


