JavaScript | 非同期処理:非同期の基礎概念 – 同期処理と非同期処理の違い

JavaScript JavaScript
スポンサーリンク

同期処理と非同期処理の一番大事なイメージ

まず、抽象的な言葉を捨てて、イメージから掴みにいきます。

同期処理は、「一列に並んで順番待ちする世界」 です。
前の人の処理が終わるまで、次の人は絶対に動けません。

非同期処理は、「順番待ちの札だけ渡して、結果はあとで受け取る世界」 です。
待っているあいだも、他の仕事をどんどん進められます。

JavaScript は基本「1 本のメインスレッド」で動くので、
この「待っている間も他のことをする」ために非同期がとても重要になります。


まずは同期処理から:一列に並ぶ世界

同期処理の流れ(「終わるまで次に行かない」)

典型的な同期処理のコードを見てみます。

function step1() {
  console.log("1. データを計算中...");
}

function step2() {
  console.log("2. 計算結果を画面に表示");
}

step1(); // これが完全に終わるまで
step2(); // ここには絶対に来ない
JavaScript

この世界では、

  1. step1() が呼ばれる
  2. step1() の処理が全部終わる
  3. その後に step2() に進む

という「カチッとした順番」が守られます。

途中で step1() がめちゃくちゃ重くなったら、その間ずっと止まります。
その間、他の処理も「何もできない」状態になります。

ブラウザなら「画面が固まった」「クリックに反応しない」状態がまさにこれです。

コンビニのレジに例えると

同期処理は、コンビニのレジが 1 台だけあって、
お客さんが 1 人ずつ並んでいる状態です。

前の人の会計が終わるまで、次の人は絶対に動けません。

レジの人(JavaScript エンジン)はプロフェッショナルですが、
1 人ずつしか相手にできないので、
前の人の処理が長引くと、後ろがどんどん詰まっていきます。


非同期処理の世界:待っている間も動き続ける

非同期処理の流れ(「終わる前に次に行く」)

今度は、典型的な非同期処理のコードを見てみます。
とりあえず setTimeout で「時間のかかる処理」の代わりをします。

console.log("A: 処理開始");

setTimeout(() => {
  console.log("B: 重い処理が完了(2秒かかったとする)");
}, 2000);

console.log("C: 他の処理を先に進める");
JavaScript

実行順はこうなります。

  1. “A: 処理開始” がすぐ出る
  2. setTimeout によって「2秒後にやってね」と予約される
  3. “C: 他の処理を先に進める” がすぐ出る
  4. 2秒経ったあとで “B: 重い処理が完了” が出る

ポイントは、「B が終わるまで C を待たない」 というところです。

setTimeout の中身は「あとで実行」という予約をしているだけで、
呼び出し自体はすぐ終わります。

だから JavaScript は、「待っているあいだ」に他の行をどんどん実行していける。

ラーメン屋の注文に例えると

非同期処理は、ラーメン屋の注文に近いです。

  1. 店員さんに「味噌ラーメンください」と注文する
  2. 店員さんは「はい」と言ってキッチンに回す
  3. その間、店員さんは別のお客さんの注文を取ったり、会計をしたりする
  4. ラーメンができたら「お待たせしました」と持ってくる

「ラーメンができるまで、店員さんがずっと手を止めて待つ」ことはしません。
これが非同期です。

JavaScript の非同期処理も同じで、

  • 「サーバーにデータを取りに行く」
  • 「ファイルを読む」
  • 「タイマーで数秒待つ」

といった「時間がかかる処理」を、「注文だけ出して、結果はあとで受け取る」 スタイルにします。


JavaScript で「非同期にしたい典型パターン」

パターン1:サーバー通信(fetch)

ネットワーク越しにサーバーとやりとりするときは、絶対に時間がかかります。

console.log("1: リクエスト前");

fetch("https://example.com/data.json")
  .then((response) => response.json())
  .then((data) => {
    console.log("3: データ取得完了", data);
  });

console.log("2: 他の処理を続ける");
JavaScript

実行順は、だいたいこうなります。

  1. “1: リクエスト前”
  2. fetch(...) で「サーバーに取りに行って」と依頼 → すぐ終わる
  3. “2: 他の処理を続ける”
  4. サーバーからレスポンスが返ってきたタイミングで “3: データ取得完了”

もしこれを同期的にやろうとしたら、
サーバーの返事を待つあいだずっと JavaScript が止まり、
画面は固まり、ユーザーの操作にも反応できなくなります。

パターン2:時間のかかる計算(本当は分けたい)

本当に重い計算を同期処理で書くと、
その間 UI が固まります。

function heavyCalc() {
  const start = Date.now();
  while (Date.now() - start < 3000) {
    // 3秒間ひたすら何かするイメージ
  }
  console.log("重い計算が終わった");
}

console.log("A");
heavyCalc(); // この間、画面は固まる
console.log("B");
JavaScript

実行順は “A” → 3 秒間固まる → “重い計算” → “B”。

もしユーザーがこの 3 秒間にボタンを押しても、
イベントは「終わるまで処理されない」状態になります。

だからこそ、「待ち時間が発生する処理」は極力非同期に逃がす設計が重要です。


同期と非同期で「コードの書き方」がどう変わるか

同期のときの「素直な順番」

同期処理だと、素直にこう書けます。

const data = getDataSync();       // 1. データを取得(終わるまで止まる)
const processed = process(data);  // 2. 加工
render(processed);                // 3. 画面に描画
JavaScript

1 が終わらないと 2 に行けません。
「上から順番に読めば、そのまま実行順になっている」状態です。

非同期だと「結果はあとで」の形になる

非同期にすると、「結果が来たときにやること」を別の場所に書きます。

getDataAsync().then((data) => {
  const processed = process(data);
  render(processed);
});

console.log("ここはデータを待たずに実行される");
JavaScript

または async/await を使うと、見た目は同期っぽく書けます。

async function main() {
  const data = await getDataAsync(); // ここで「待つ」けれど、他の処理は進められる
  const processed = process(data);
  render(processed);
}

main();
console.log("main の中の await を待たずに、これはすぐ実行される");
JavaScript

ここが重要です。
同期処理は「値をすぐ返す関数」と相性が良い。
非同期処理は「Promise を返し、結果は then や await の先で扱う」スタイルになる。

これが「非同期を扱うために Promise や async/await が必要になる」根っこの理由です。


「なぜ全部同期で書かないの?」という根本の話

JavaScript は基本「1 本のメインスレッド」だから

ブラウザの JavaScript は、基本的に 1 つのスレッド(主役)で動いています。
この 1 本が

  • イベント処理(クリック、キー入力)
  • 描画の更新
  • あなたの書いた JS コード

すべてを面倒みています。

もし時間のかかる処理を同期でやると、その間ずっとこの 1 本が塞がれてしまい、
クリックにもスクロールにも応答できなくなります。

ユーザーから見ると「固まった」「落ちた?」という体験になります。

非同期処理で「待ち時間」を外に追い出す

非同期処理を使うことで、

  • 「サーバーの返事待ち」
  • 「タイマーで数秒待機」
  • 「ファイル読み込み」

などの「時間がかかる仕事」を、
メインスレッドの外側に追い出し、結果だけあとでメインスレッドに届けてもらう
という構造にできます。

JavaScript はその間、他のイベント処理や描画更新を続けられるので、
アプリ全体として「サクサク動いている」印象を保てます。


まとめ:同期 vs 非同期を一言で

最後に、感覚を固めます。

同期処理は、
「前の処理が終わるまで絶対に次に進まない、一列の世界」
シンプルで分かりやすいけれど、時間のかかる処理を入れると全体が止まる。

非同期処理は、
「時間のかかる処理は“注文だけ出して”おき、待っている間も他の仕事を進める世界」
書き方は少し複雑になるけれど、アプリをなめらかに保てる。

そして JavaScript では、

  • サーバー通信(fetch)
  • タイマー(setTimeout, setInterval)
  • ファイルI/O(Node.js)

などは、基本すべて非同期で扱うのが前提になっています。

この「列に並ぶ世界」と「注文して待つ世界」の違いが腑に落ちると、
Promise や async/await を学ぶときに、
「ああこれは“注文して待つ側の文法”なんだな」と自然に理解できるようになります。

タイトルとURLをコピーしました