JavaScript | 非同期処理:非同期の基礎概念 – Web API の役割

JavaScript JavaScript
スポンサーリンク

全体像:Web API は「JavaScript の外にいる助っ人」

まず前提から整理します。

ブラウザの中で JavaScript が動くとき、

  • JavaScript エンジン(言語そのものを実行する脳みそ)
  • Web API(ブラウザが提供する「いろんな便利機能」の窓口)
  • イベントループとタスクキュー(「あとでやる処理」を管理する仕組み)

が、一緒に仕事をしています。

このうち Web API は「JavaScript ではできないことを、ブラウザが代わりに請け負うための入り口」 です。
非同期処理の文脈では特に、

  • 時間がかかる処理(タイマー・通信・DOM イベント)を、JavaScript 本体から切り離して担当する
  • 終わったら「これ実行していいよ」とコールバックをキューに積む

という役割を担っています。

ここが重要です。
JavaScript はシングルスレッドで 1 本しかありませんが、
Web API が「外で待つ・外で仕事をする」を担当してくれるからこそ、JavaScript はブロッキングせずに済む、という構造になっています。


Web API って具体的に何を指しているのか

JavaScript の「組み込み」ではなく、ブラウザ側が提供している機能

setTimeout, fetch, DOM(document, window), addEventListener, localStorage など、
ブラウザ環境で使える多くの機能は「言語仕様(ECMAScript)」ではなく「Web API」として定義されています。

例えば、次のコードを見てください。

setTimeout(() => {
  console.log("3秒後");
}, 3000);
JavaScript

ここで setTimeout 自体は JavaScript のコア言語の一部ではなく、
ブラウザ(や Node.js)が「タイマー機能の API」として提供しているものです。

JavaScript エンジンは、

「3秒待つ」
「待っている間、他の処理を続ける」

といったことは自前ではできません。
「○ミリ秒後にこれ実行して」と Web API に依頼し、
あとは結果が返ってくるのを待つだけ です。

Web API のざっくりした担当範囲

代表的なものだけ挙げると、Web API はこんな領域を担当しています。

  • タイマー(setTimeout, setInterval
  • DOM 操作とイベント(document, addEventListener など)
  • XHR / fetch(ネットワーク通信)
  • Web Storage(localStorage, sessionStorage
  • Web Workers(別スレッド)
  • その他:Geolocation, WebSocket, Canvas, Audio/Video などたくさん

非同期処理の基礎では、主に
「タイマー」「イベント」「ネットワーク」という 3 つが登場します。


具体例1:setTimeout と Web API(「待つ」の担当を外に出す)

まずコードから動きを追う

console.log("A: start");

setTimeout(() => {
  console.log("B: 2秒後の処理");
}, 2000);

console.log("C: end");
JavaScript

実行すると、出力はこうなります。

A: start
C: end
B: 2秒後の処理

このとき「中で何が起きているか」を分解してみます。

裏側で起きていること(ざっくり)

  1. JavaScript エンジンが "A: start" を実行
  2. setTimeout を呼ぶ
    • 「2秒後にこのコールバックを実行して」と Web API(タイマー機能)に依頼
    • ここまでで JavaScript の仕事は一旦終わり。コールスタックからは setTimeout の呼び出しが消える
  3. JavaScript はすぐ次に進み、"C: end" を実行
  4. 一方、ブラウザ内部のタイマー機構(Web API)が、2秒間カウントダウン
    JavaScript のメインスレッドはこの間も他の仕事ができる
  5. 2秒経ったら、Web API が「コールバックをタスクキューに積む」
  6. イベントループが「メインスレッドが空いたタイミング」で、そのコールバックを実行
    "B: 2秒後の処理" が出力される

ここが重要です。
「2秒待つ」のは Web API の仕事であって、JavaScript 本体は「待ち続けている」わけではない
だから、待ち時間のあいだも UI イベントや他の処理を進められるのです。


具体例2:fetch と Web API(ネットワークも「外注」している)

コードと実行順

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

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

console.log("2: 他の処理");
JavaScript

出力の順番は

1: リクエスト前
2: 他の処理
3: データ取得

のようになります。

裏側での流れ

  1. "1: リクエスト前" を出力
  2. fetch を呼び出す
    • JavaScript エンジンは、「この URL に HTTP リクエストを送って、結果が来たら教えて」と Web API に依頼
    • このとき、実際のネットワーク通信はブラウザ側の機能(Web API)が担当
    • fetch はすぐに Promise を返し、JavaScript の処理は先に進む
  3. "2: 他の処理" を出力
  4. ネットワークの結果が返ってきたら、Web API が「この Promise を解決しなさい」とエンジンに知らせる
    実際には、「then に渡したコールバック」をタスクキュー(正確にはマイクロタスクキュー)に積む
  5. イベントループがそれを実行し、"3: データ取得" が出力される

ここでのポイントも同じです。
ネットワークの「送信」や「待機」は JavaScript の外(Web API)で行われる
JavaScript は「依頼をしたらすぐ次に進む」「結果が来たときだけコールバックで受け取る」役割に徹しています。


具体例3:DOM イベントと Web API(「ユーザーの操作監視」担当)

イベントリスナーの動き

const button = document.querySelector("#btn");

button.addEventListener("click", () => {
  console.log("ボタンがクリックされました");
});
JavaScript

このコードを書いた時点では、まだ何も起きません。
ボタンが押されたときに初めて "ボタンがクリックされました" が出力されます。

裏側では誰が「クリックされたこと」を検知しているか

  1. addEventListener を呼ぶと、「この要素にクリックイベントが来たら、この関数を呼んで」という情報が Web API 側に登録される
  2. その後、ユーザーがボタンをクリックすると、ブラウザのネイティブコードがそれを検知
  3. 「クリックが起きた」というイベントが Web API 層からタスクキューに渡される
  4. イベントループがそれを拾い、メインスレッドでコールバック(無名関数)を実行
  5. "ボタンがクリックされました" が出力される

ここが重要です。
ユーザーの操作(クリック、スクロール、キー入力など)を「監視し続けている」のは JavaScript 本体ではなく、ブラウザのネイティブ部分=Web API 側
JavaScript は「イベントが発生したら呼ばれるコールバックを登録しておく」だけです。


なぜ Web API が非同期処理でそんなに重要なのか

JavaScript は「できること」が限られているから

ECMAScript(言語仕様)としての JavaScript は、本質的には

  • 変数・関数・クラス
  • 配列やオブジェクト
  • 数学演算や文字列操作

のような「計算」のための機能に集中しています。

一方、実際のアプリ開発では、

  • 時間を測る
  • ファイルやネットワークにアクセスする
  • ユーザー操作を受け取る
  • 画面を描画する

といった「外側の世界」とのやりとりが必要です。

これらは、JavaScript 単体ではどうにもできません。
だからこそ、ブラウザ(や Node.js)が ホスト環境として Web API を提供し、外側との橋渡しをしている わけです。

シングルスレッドでも「止まらない」ための鍵になっている

もし JavaScript 自身が

  • 3秒間待つ(タイマー)
  • サーバーの返事を待つ(ネットワーク)
  • ユーザーのクリックを延々待つ(イベントループ)

といったことをすべて自前でやっていたら、

その待ち時間のあいだ、メインスレッドは完全にブロックされてしまいます。

実際には、

  • 待つ・監視する → Web API
  • 結果が出たら「この処理を実行して」とタスクキューに依頼 → イベントループが拾ってメインスレッドで実行

という分業をすることで、
「シングルスレッドだけどノンブロッキング」 な実行モデルを成立させています。

ここが重要です。
非同期処理の大枠は、

JavaScript 本体は「依頼」と「結果を受け取る処理」だけ書く。
その間の「待つ」「外の世界とやりとりする」は Web API が担当する。

という役割分担だ、と理解しておくとスッキリします。


まとめ:Web API の役割を一言でいうと

Web API の役割を一文でまとめると、

「ブラウザやホスト環境が持っている機能(タイマー・ネットワーク・DOM・イベントなど)を、JavaScript から使えるようにし、時間のかかる処理を JavaScript の外側で引き受ける窓口」

です。

押さえておきたいポイントは次の通りです。

JavaScript エンジンは計算担当で、タイマー・通信・イベント監視などは Web API が担当している。
setTimeoutfetch は「待つ」のではなく、「Web API に依頼して、結果が来たらコールバックをキューに積んでもらう」仕組み。
DOM イベントも、ユーザーの操作を検知しているのはブラウザ側(Web API)で、JavaScript はコールバック登録だけする。
この分業のおかげで、JavaScript はシングルスレッドなのに、待ち時間中もブロックされずに他の処理を続けられる。

これを前提として、

  • コールスタック(今どこを実行中か)
  • タスクキュー(あとで実行する処理の待ち行列)
  • イベントループ(キューから仕事を持ってくる係)

の話を重ねていくと、「JavaScript の非同期モデル」が一本の線でつながってきます。

まずは、

  • setTimeout
  • fetch
  • addEventListener

あたりについて、「これは JavaScript そのものじゃなくて Web API 側の機能なんだ」と意識しながらコードを書いてみてください。
それだけで、非同期処理の見え方がかなり変わってくるはずです。

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