---
title: "非同期処理とは？同期処理との違いから実装方式まで実装者目線で解説"
url: "https://www.issoh.co.jp/tech/details/13590/"
published: 2026-07-12
updated: 2026-09-17
categories: ["アーキテクチャ"]
publisher: "株式会社一創"
---

# 非同期処理とは？同期処理との違いから実装方式まで実装者目線で解説

非同期処理とは、ある処理の完了を待たずに、その先の処理へ進める実行方式のことです。データベースへの問い合わせや外部APIの呼び出しなど、結果が返るまで時間のかかる「待ち」の間も、プログラムを止めずに別の仕事を進められます。この記事では、非同期処理の定義と同期処理との違いから、並行・並列との区別、イベントループやメッセージキューといった仕組み、コールバック・Promise・async/await という実装の進化、JavaScriptやPython・Java・Goでの書き方、そして非同期を採用すべき場面と見送るべき場面までを、実装者と発注者の双方が判断に使える形で整理する記事です。同期と非同期でどれだけ所要時間が変わるかは、記事中に置いたNode.jsとPythonの実行コードをそのまま動かせば手元で確かめられます。仕様や版番号の記述は、MDN・nodejs.org・docs.python.org・openjdk.org・go.dev・AWS公式ドキュメントを2026年9月時点で参照した内容に合わせています。

## まとめ｜非同期処理の要点と使いどころ

非同期処理の本質は、待ち時間を遊ばせないことにあります。1件の処理が結果を返すまで手を止める同期処理に対し、非同期処理は待っている間に別の処理へ着手し、結果が届いたところで続きを再開します。効果が大きいのは、通信やファイル入出力のように「CPUは暇なのに応答を待っている」時間が長いI/Oバウンドな処理です。逆に、計算そのものが重いCPUバウンドな処理では、非同期にしても総時間は縮みません。

実装の主流は、コールバックから始まり、Promiseを経て async/await へと書き方が整理されてきました。JavaScriptのイベントループ、Pythonのasyncio、Goのゴルーチンのように、言語ごとに得意なやり方があります。バックエンドで重い処理を切り離すときは、メッセージキューとワーカーに逃がす構成が定番です。ただし非同期化は万能ではなく、処理順序の保証やデバッグの難しさ、同じ処理が二重に走るリスクも無視できません。だからこそ、失敗時にリトライしても壊れない設計（冪等性の担保）が前提になります。

数字で言うと、1秒かかるI/Oを3件こなす処理は、逐次に待てば約3秒、並行に投げれば約1秒に収まります。この差は記事中のコードで再現できる範囲の話であって、CPUの計算そのものが速くなるわけではありません。以降で定義・仕組み・実測・実装・採用判断を順に見ていきます。

## 非同期処理とは｜完了を待たずに次の処理へ進める実行方式の定義

まず言葉の輪郭を固めます。非同期処理を「速くする技術」とだけ捉えると、後半の実装や採用判断がぶれます。非同期処理は速度そのものより、待ち時間の使い方を変える方式だという点が出発点です。

### 非同期処理の定義：処理の完了を待たずに呼び出し元へ制御を返す方式

非同期処理とは、時間のかかる処理を呼び出したとき、その完了を待たずに呼び出し元へ制御を返し、結果は後から受け取る仕組みを指します。たとえば外部APIに「データをください」と依頼した瞬間に、返事を待たずに画面の描画やほかの計算を進め、返事が届いたら受け取り口（コールバックやPromise）で続きを処理します。依頼と結果の受け取りが時間的に分離しているのが特徴です。処理を始めた順番と、結果が返る順番が一致しない場合がある、と言い換えてもかまいません。JavaScriptの言語仕様でいえば、この「まだ決まっていない結果」を表すのが[MDNのPromiseリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global%5FObjects/Promise)にある3つの状態（pending・fulfilled・rejected）で、依頼した瞬間はpending、結果が確定した時点でfulfilledかrejectedに落ち着きます。

### 同期処理との違い：待ち時間の扱い方と全体スループットの差が出る理由

同期処理は、1つの処理が終わるまで次に進みません。窓口が1つのレジで、前の客の会計が済むまで後ろが待つ状態です。非同期処理は、会計の裏で袋詰めや次の注文受付を並行して進めるイメージに近くなります。決定的な差は、待ち時間に別の仕事を差し込めるかどうかです。3件のAPI呼び出しがそれぞれ1秒かかる場合、同期なら合計3秒ですが、非同期で同時に投げれば全体を約1秒に縮められます。単体の処理が速くなるのではなく、待ちが重なる分だけ全体のスループット（単位時間あたりの処理量）が上がる、という効き方をします。

| 観点        | 同期処理       | 非同期処理         |
| --------- | ---------- | ------------- |
| 次の処理の開始   | 前の処理の完了後   | 完了を待たずに開始     |
| 待ち時間の扱い   | 待つ（ブロックする） | 別の処理を進める      |
| コードの読みやすさ | 上から順で追いやすい | 結果の受け取り口が分かれる |
| 向く処理      | 逐次・整合性重視   | I/O待ちが多い・高並行  |

非同期API設計では、依頼を受け付けてすぐ応答を返し、結果は後からポーリングやWebhookで受け取る形をとることがあります。この受け取り方の設計はAPIの流儀に関わるため、[RESTの仕組みと設計原則](https://www.issoh.co.jp/tech/details/13588/)を押さえておくと、非同期エンドポイントの組み立てが楽になります。

### 並行処理・並列処理・マルチスレッドと非同期処理の違いを正しく整理

非同期と混同されやすいのが並行（Concurrency）と並列（Parallelism）です。並行は「複数の処理を切り替えながら進める」考え方で、非同期処理はこれを実現する手段の1つです。並列は「複数のCPUコアで文字どおり同時に実行する」ことを指し、計算そのものを分担します。単一スレッドでもイベントループで並行は成立しますが、並列には物理的なコアが要る点が決定的な差です。非同期処理は必ずしもマルチスレッドではなく、JavaScriptのように1スレッドで非同期を回す方式もあります。「非同期＝複数コアで速くなる」は誤解で、非同期が縮めるのは計算時間ではなく待ち時間です。

ブラウザで本当に並列実行したい場合の受け皿は別にあります。MDNの[ウェブワーカーの使用](https://developer.mozilla.org/ja/docs/Web/API/Web%5FWorkers%5FAPI/Using%5Fweb%5Fworkers)が示すとおり、Web Workerはメインスレッドとは別のスレッドでスクリプトを走らせ、DOMへは直接触れずメッセージでやり取りします。非同期はメインスレッドの待ちを埋める道具、Workerは計算そのものを逃がす道具、という役割の違いで覚えておくと混同しません。ブラウザ側の切り分けは[Web Workerで重い処理を別スレッドへ逃がす実装](https://www.issoh.co.jp/tech/details/3444/)で具体のコードとともに確認できます。

## 同期と非同期の差を手元で測るNode.jsとPythonの実行コード

ここまでの説明は、コードを2本動かせば数字で確かめられます。どちらも外部パッケージなしで走り、待ち時間が重なる処理でだけ差が出ることを、コンソールの経過時間として観察できます。

### Node.jsで逐次awaitとPromise.allの所要時間を比べる実行例

1秒かかるI/Oを模したダミー関数を3回呼び、逐次に待つ場合と同時に投げる場合を計測します。拡張子を `.mjs` にして保存し、`node async-demo.mjs` で実行してください。トップレベルawaitを使うため、CommonJSではなくESモジュールとして動かす点だけ注意します。

```
const wait = (ms) => new Promise((ok) => setTimeout(ok, ms));
const fetchUser = async (id) => {
  await wait(1000);
  return { id };
};

async function sequential() {
  console.time('sequential');
  await fetchUser(1);
  await fetchUser(2);
  await fetchUser(3);
  console.timeEnd('sequential');
}

async function parallel() {
  console.time('parallel');
  await Promise.all([fetchUser(1), fetchUser(2), fetchUser(3)]);
  console.timeEnd('parallel');
}

await sequential();
await parallel();
```

手元で走らせると、sequential はおよそ3,000ミリ秒、parallel はおよそ1,000ミリ秒を示します。3件のうち2件ぶんの待ち時間が消えたわけではなく、重ねて待っただけです。ここを `Promise.all` から `Promise.allSettled` に替えると、1件が失敗しても残りの結果を受け取れます。エラー時の挙動の違いと使い分けは[Promise.allとallSettledの選び分け](https://www.issoh.co.jp/tech/details/3691/)で整理している内容です。なお実行に使うランタイムの版は、[Node.jsの公式リリース一覧](https://nodejs.org/en/about/previous-releases)で確認できます。2026年9月時点ではv26系がCurrent、v24系（Krypton）とv22系（Jod）がLTSで、LTSは重大バグ修正が合計30か月保証される仕組みです。同ページには、v27系から年次リリースへ移り、すべてのメジャー版が6か月のCurrent期間を経てLTSへ移行する方針も記載されています。本番環境はActive LTSかMaintenance LTSを選ぶのが公式の推奨です。

### PythonのTaskGroupで3件のI/Oを並行に走らせる実行例

Python側でも同じ実験ができます。`asyncio.TaskGroup` は、複数のタスクをまとめて起動し、ブロックを抜けるところで全件の完了を待つ書き方です。[公式ドキュメントのCoroutines and tasks](https://docs.python.org/3/library/asyncio-task.html)には「TaskGroupは create\_task() のより新しい代替である」と記され、追加は3.11からと明記されています。参照した現行ドキュメントは3.14.7系の表示です。

```
import asyncio
import time

async def fetch(name, sec):
    await asyncio.sleep(sec)
    return name

async def main():
    start = time.perf_counter()
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(fetch("db", 1))
        t2 = tg.create_task(fetch("api", 1))
        t3 = tg.create_task(fetch("file", 1))
    print(t1.result(), t2.result(), t3.result())
    print(f"elapsed: {time.perf_counter() - start:.2f}s")

asyncio.run(main())
```

出力の elapsed はおよそ1.00秒です。`await fetch(...)` を3行並べる書き方に替えると約3.00秒になり、Node.jsの実験と同じ差が再現します。同じドキュメントには3.12で追加された eager task factory の説明もあり、コルーチンが最初にブロックするまで同期的に実行することでタスク投入のオーバーヘッドを削る仕組みが紹介されています。ただし既存アプリのタスク実行順が変わる可能性がある、という注意書きも併記されているため、既存システムへ後から入れる場合は順序に依存した処理がないかを先に洗い出してください。

## 非同期処理が効く場面と仕組み｜I/O待ち・イベントループ・キュー

非同期処理は、どこでも一律に速くする道具ではありません。効くのは待ちが発生する場所に限られます。ここでは、なぜI/Oで効くのか、内部でどう動くのかを具体的に見ます。

### I/O待ち（DB・外部API・ファイル）の処理でこそ効く理由

処理は大きく、CPUが計算し続けるCPUバウンドと、外部の応答を待つI/Oバウンドに分かれます。データベースへの問い合わせ、外部APIの呼び出し、ファイルの読み書き、ネットワーク通信は、いずれも依頼を出してから結果が返るまでCPUは基本的に暇です。同期処理ではこの空き時間をただ待って捨てますが、非同期処理なら別の依頼を投げたり、届いた結果の処理に回したりできます。Webサーバーが同時に多数のリクエストをさばけるのは、各リクエストのDB待ちの間に別のリクエストを処理しているからです。逆に、画像のリサイズや数値計算のようなCPUバウンドな処理は待ちがないため、非同期化しても総時間は変わりません。

### イベントループとノンブロッキングI/Oが待ちを埋めて回る動き

単一スレッドで非同期を成立させる中心的な仕組みが、イベントループです。処理を「今すぐ実行できるもの」と「結果待ちのもの」に振り分け、待ちの間はキューに積んだ次のタスクを実行し、結果が届いたら対応する続き（コールバック）を呼び出します。これを支えるのがノンブロッキングI/Oで、I/Oの依頼を出した時点で制御を即座に返し、スレッドを待ちで固定しません。Node.jsやPythonのasyncioはこのモデルで、1スレッドでも数千の接続を同時にさばけます。ポイントは、暇な待ち時間を1本のスレッドが忙しく回して埋めている、という点です。

この「1本のループ」は、実際には段階に分かれています。[Node.js公式のイベントループ解説](https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick)は、1回転をtimers・pending callbacks・poll・checkなどのフェーズに分け、`setTimeout` はtimersフェーズ、`setImmediate` はcheckフェーズで実行されると説明しています。JavaScriptの言語側の約束事は[MDNのJavaScript実行モデル](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Execution%5Fmodel)にまとまっていて、実行中の関数は途中で割り込まれない（run-to-completion）ため、重い同期処理を1つ挟むだけでループ全体が止まる仕組みです。「非同期なのに固まる」障害の多くは、この性質を踏み外したところで起きます。

### メッセージキューとワーカーで重い処理を切り離す非同期処理の構成

バックエンドで時間のかかる処理を切り離すときは、言語のイベントループとは別に、メッセージキューとワーカーを使った構成が定番です。ユーザーからの依頼（メール送信、動画変換、帳票生成など）をいったんキューに積み、応答はすぐ返す。実際の重い処理は、キューを監視するワーカー（別プロセス）が後から取り出して実行します。この分離により、Webサーバーは待たされません。処理量が急増しても、未処理分はキューに溜めて順に消化していきます。負荷に応じてワーカーの台数を増減させれば、繁忙時のさばきも安定します。こうしたキューやワーカーをクラウド上に組む設計は、次章の採用判断にも関わる論点です。Node.jsで同じ構成を組むなら、[BullMQによるジョブキュー実装と採用判断](https://www.issoh.co.jp/tech/details/17289/)で再試行・レート制限・ワーカー常駐の具体を確認できます。

マネージドキューを選ぶ場合、配信保証の型を最初に確かめてください。[Amazon SQSの標準キューの公式ドキュメント](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)は、標準キューが at-least-once 配信であり、分散構成ゆえに同じメッセージのコピーが複数届くことも、順序が前後することもあると明記しています。つまり二重実行は例外ではなく仕様の範囲です。AWS内でどのキューや通知サービスを選ぶかは[SQS・SNS・SESの違いと使い分け](https://www.issoh.co.jp/tech/details/9310/)に判断軸をまとめてあります。キューを起点に業務全体を組み替える段階まで進むなら、[イベント駆動アーキテクチャの実装パターンと採用判断](https://www.issoh.co.jp/tech/details/13226/)が上位の設計論として続きます。

## 非同期処理の実装方式｜コールバック・Promise・async/await・言語別

非同期の「結果を後から受け取る」をコードでどう書くかは、歴史的に整理が進んできました。ここでは書き方の進化と、言語ごとの実装、そしてリトライ設計の勘所を押さえます。

### コールバックからPromise・async/awaitへの進化とコールバック地獄

最初期の非同期は、処理の完了時に呼ばれる関数（コールバック）を渡す方式でした。単純ですが、非同期処理を連鎖させると関数が入れ子になり、いわゆる「コールバック地獄」で可読性が崩れます。これを解いたのがPromiseで、非同期の結果を「まだ決まっていない値」というオブジェクトとして扱い、成功（resolve）と失敗（reject）を `.then` や `.catch` でつなぎます。さらに async/await は、そのPromiseを同期処理のように上から下へ書ける構文糖で、await を置いた行で結果が返るまで待ってから次へ進むように読めるのが特徴です。見た目は同期に近いのに、裏では非同期に動くのが利点です。

この対応関係は仕様の説明にも表れています。[MDNのasync function](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async%5Ffunction)は、async関数が必ずPromiseを返し、返り値がPromiseでなければ解決済みのPromiseに包まれること、関数内で投げられた例外はrejectされたPromiseになることを定義しています。async/awaitはPromiseを置き換える別物ではなく、同じ土台の上に載った書き方です。ここを取り違えると、try/catchで捕まえられる例外と、捕まえられずに未処理のrejectになる例外の線引きを見誤ります。

### 言語別の実装（JavaScript・Python・Java・Go）と設計思想の違い

非同期の実現方式は言語ごとに設計思想が異なります。代表的なものを整理します。

| 言語         | 主な方式                     | 特徴                      |
| ---------- | ------------------------ | ----------------------- |
| JavaScript | Promise / async/await    | 単一スレッド＋イベントループで多数接続をさばく |
| Python     | `asyncio` / async def    | イベントループ方式。I/Oバウンド向け     |
| Java       | CompletableFuture・仮想スレッド | スレッドプール中心。仮想スレッドで軽量化    |
| Go         | ゴルーチン / チャネル             | 軽量スレッドを言語が管理。並行を書きやすい   |
| PHP        | Fiber・ReactPHP・Swoole    | 既定は同期。拡張で並行化する          |

JavaScriptとPythonは1スレッドのイベントループで待ちを回すのに対し、Goはゴルーチンという軽量な実行単位を大量に走らせ、ランタイムがコアへ割り当てます。[Effective Go](https://go.dev/doc/effective%5Fgo)はゴルーチンを「スタック領域の確保程度のコストしかかからない軽量な存在で、複数のOSスレッドへ多重化されるため、1つがI/O待ちでブロックしても他は走り続ける」と説明しています。待ちを埋める仕組みか、実行単位そのものを増やす仕組みか、という設計思想の差がここでの違いです。PHPのように既定が同期で、Fiberや拡張を入れて初めて並行に踏み込む言語もあり、[PHPの非同期処理とFiber・ReactPHP・Swooleの違い](https://www.issoh.co.jp/tech/details/2764/)で実装の選択肢を比較しています。

Javaは仮想スレッドに関する変更が大きい領域です。[JEP 444: Virtual Threads](https://openjdk.org/jeps/444)はステータスがClosed/Delivered、対象リリースが21と記録されており、仮想スレッドはJDK 21で正式機能になりました。さらに[JEP 491: Synchronize Virtual Threads without Pinning](https://openjdk.org/jeps/491)がJDK 24でDeliveredとなり、synchronizedメソッドやブロックで待つ仮想スレッドが土台のプラットフォームスレッドを手放すようになった結果、ピン留めされる場面がほぼ解消しています。JDK 21から23で仮想スレッドを試して「synchronizedのせいでスループットが伸びない」と判断した場合、24以降で前提が変わっている点を確かめ直してください。仕組みと詰まりどころは[Java仮想スレッドとProject Loomの落とし穴](https://www.issoh.co.jp/tech/details/3209/)に実務目線でまとめています。iOSアプリのSwiftでも、[Combineとasync/awaitの役割分担](https://www.issoh.co.jp/tech/details/15805/)が同じ論点になります。

### エラーハンドリングとリトライ時に冪等性の担保が要る理由と設計

非同期処理では、失敗の扱いが同期より難しくなります。呼び出し元は結果を待っていないため、例外はコールバックやPromiseのreject、あるいはキューの再試行として非同期に返ってくるのが同期処理との違いです。ネットワークの一時障害でリトライを掛けるのは定石ですが、ここに落とし穴があります。「送信は成功していたのに応答だけ失われた」場合、リトライで同じ処理が二重に走り、注文の二重登録や請求の重複という事故につながりかねません。これを防ぐ設計原則が冪等性で、同じリクエストを何度実行しても結果が1回分と同じになるようにします。非同期とリトライを組み合わせるなら、[冪等性の担保方法](https://www.issoh.co.jp/tech/details/13382/)をセットで設計しておくと、再試行しても壊れない処理になります。

実装としては、受け取ったメッセージのIDを主キーに持つ処理済みテーブルを用意し、登録できたときだけ本処理へ進む形が扱いやすい部類です。PostgreSQLなら次のように書けます。

```
CREATE TABLE processed_messages (
  message_id text PRIMARY KEY,
  processed_at timestamptz NOT NULL DEFAULT now()
);

INSERT INTO processed_messages (message_id)
VALUES ($1)
ON CONFLICT (message_id) DO NOTHING
RETURNING message_id;
```

行が返れば初回、返らなければ処理済みなので本処理を飛ばします。キュー側の機能で守れる範囲も押さえておきたいところです。[SQS FIFOキューの exactly-once processing](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-exactly-once-processing.html)は、5分間の重複排除インターバル内に同じ内容を再送しても重複を投入しないこと、コンテンツベースの重複排除ではメッセージ本文（属性は含まない）のSHA-256ハッシュから重複排除IDを生成することを説明しています。守られるのは「キューへの投入」であって、ワーカー側の二重実行ではありません。5分を超える再送やワーカーの再試行は、上のテーブルのようなアプリ側の冪等性で受け止める必要があります。

## 非同期処理を採用すべき場面と見送るべき場面を分ける実務の判断基準

非同期は書き方が増える分、コードとデバッグの難易度も上がります。どこで採り、どこで採らないか、その線引きが設計の肝です。「ケースバイケース」で逃げず、判断の軸を条件付きで示します。

### 採用すべき条件：I/Oバウンド・高並行・体感速度が要る場面の見極め

非同期を積極的に採るべきなのは、次の条件がそろう場面です。まず、DBや外部API・ファイルなどI/O待ちが処理時間の多くを占めること。次に、多数のリクエストを同時にさばく必要があること（Webサーバー、チャット、配信基盤など）。そして、ユーザーが結果を待つ間も画面を固めたくない、体感速度が売りになる画面。これらでは、待ち時間を別の処理で埋める非同期の効果がそのまま応答性と処理量に跳ね返ります。フロントエンドでも、データ取得中に画面の描画を止めない設計が体感を左右する場面です。この画面側の描画の考え方は[レンダリングの仕組み](https://www.issoh.co.jp/tech/details/13578/)と合わせて捉えると整理しやすくなります。

### 見送るべき場面：CPUバウンド・単純な逐次処理・整合性最優先の箇所

逆に、非同期を持ち込まないほうがよい場面もはっきりあります。画像処理や機械学習の推論のようなCPUバウンドな処理は、待ちがないため非同期にしても速くならず、むしろ実装の複雑さだけが増えます（この場合は並列処理やワーカー分散で別途対処します）。上から順に実行するだけの単純なバッチや管理用スクリプトも、同期のまま書いたほうが読みやすく壊れにくいです。さらに、銀行残高の更新のように処理順序と整合性を厳密に守る必要がある箇所では、安易な非同期化は二重実行や順序逆転の温床になります。「速そうだから」で全体を非同期にするのは失敗パターンで、効くのはあくまで待ちのある箇所だけです。

### 非同期処理の設計で陥りやすい落とし穴とクラウド基盤上での実装

非同期処理の実装で詰まりやすいのは、順序保証・デバッグ・二重実行の3点です。非同期では処理の完了順が前後するため、Aの結果を使ってBを処理したいのに順番が保証されない、といった不具合が起きます。スタックトレースも呼び出し元と切り離されるため、原因の追跡は同期処理より難しくなりがちです。前述の二重実行は冪等性で守ります。順序が要る処理と要らない処理を最初に仕分けし、要るものだけをFIFOキューやメッセージグループで束ねるのが、コストを膨らませない現実的な線引きです。これらを踏まえたうえで、メッセージキュー・ワーカー・オートスケールを組み合わせた非同期基盤は、負荷変動に強い受託開発の土台になる領域です。キュー（Amazon SQS等）やサーバーレス、ワーカーのスケーリングをクラウド上に安定して構築するには、相応の設計と運用の知見が要ります。一創の[インフラ構築（AWS/GCP/Azure）](https://www.issoh.co.jp/service/system/aws/)では、非同期処理を前提とした基盤設計から運用までを支援しています。

## 非同期処理の実装・設計・言語別の使い分けに関するよくある質問

非同期処理について、実装や設計の現場でよく挙がる質問に簡潔に答えます。

### 非同期処理と同期処理はどちらが速いのですか？

処理内容によります。DBアクセスや外部API呼び出しのようにI/O待ちが多い処理では、待ち時間に別の処理を進められる非同期のほうが全体のスループットは高くなります。記事中のNode.jsの実行例では、1秒のI/Oを3件こなす処理が約3,000ミリ秒から約1,000ミリ秒に縮みました。一方、待ちのない計算中心の処理では差はほとんど出ません。非同期は個々の処理を速くするのではなく、待ちが重なる場面で全体の処理量を増やす技術だと捉えると判断を誤りません。

### async/awaitとPromiseの違いは何ですか？

両者は対立するものではなく、async/awaitはPromiseをより読みやすく書くための構文です。Promiseは非同期の結果を表すオブジェクトで、`.then` や `.catch` で処理をつなぎます。async/await はそのPromiseを、await を置いた行で待ってから次へ進むように、上から下へ同期的な見た目で書けるようにしたものです。MDNのasync functionの定義どおり、async関数は必ずPromiseを返し、関数内の例外はrejectされたPromiseになります。内部で動いているのは同じPromiseで、記述の読みやすさが違うだけです。

### 非同期処理にすればCPUの処理も速くなりますか？

速くなりません。非同期処理が縮めるのは、外部の応答を待つ「待ち時間」であって、計算そのものの時間ではありません。CPUが計算し続けるCPUバウンドな処理を速くしたい場合は、複数コアで同時に計算する並列処理や、処理を分散させるワーカー構成が適しています。ブラウザならWeb Worker、サーバーサイドなら別プロセスのワーカーへ逃がすのが定石で、Javaの仮想スレッドのような軽量スレッドもI/O待ちの多重化を狙った仕組みです。非同期と並列は目的が異なる別の技術だと切り分けてください。

### 非同期処理のデメリットは何ですか？

主に3つあります。第一にコードが複雑になり、結果の受け取り口が分かれるため読み書きの難易度が上がること。第二に、処理の完了順が前後するため、順序保証やデバッグが同期処理より難しくなること。第三に、リトライで同じ処理が二重に走るリスクがあり、冪等性を意識した設計が要ることです。三番目は運用側の仕様でもあります。Amazon SQSの標準キューは公式ドキュメントで at-least-once 配信と明記され、同じメッセージが複数回届く前提で受け手を作る必要がある仕組みです。待ちのない処理に無理に持ち込むと、これらのコストだけが増えます。

### バックエンドの重い処理はどう非同期化しますか？

メール送信や動画変換のような重い処理は、メッセージキューとワーカーに逃がすのが定番です。ユーザーの依頼をキューに積んで応答はすぐ返し、キューを監視する別プロセスのワーカーが後から実処理を担う形です。処理量が急増しても未処理分はキューに溜め、ワーカーの台数を増やして消化できます。設計時に決めるのは、順序保証が要るかどうか、重複配信をどこで吸収するか、失敗したメッセージをどのデッドレターキューへ送るかの3点です。クラウドのマネージドなキューやサーバーレスを使うと、この構成を安定して運用しやすくなります。

## 関連記事

- [非同期関数の書き方｜async宣言・await式・TypeScriptの型定義とdelay関数の実装](https://www.issoh.co.jp/tech/details/3794/)：JavaScriptとTypeScriptで実際に非同期関数を書く手順を、asyncの宣言規則・await式の位置・型定義・delay関数の実装まで扱っています。
- [JavaScriptの非同期エラーハンドリングと並列実行｜try/catch・Promise.all・allSettledの使い分け](https://www.issoh.co.jp/tech/details/3691/)：例外の伝播とfetchの失敗判定、Promise.allとallSettledの選び分け、タイムアウトとリトライの設計を実装コードで解説しています。
- [冪等性とは？読み方・意味からAPI・IaCでの担保方法まで実装者向けに解説](https://www.issoh.co.jp/tech/details/13382/)：非同期処理のリトライで二重実行を防ぐための冪等性の担保方法を、API設計の具体で掘り下げています。
- [RESTとは？REST APIの仕組みと6原則・SOAP/GraphQLとの違いを実装目線で解説](https://www.issoh.co.jp/tech/details/13588/)：非同期エンドポイントの受け取り口を設計するときに前提となる、REST APIの原則を整理しています。
- [レンダリングとは？ブラウザ描画の仕組みとCSR/SSR/SSGの違い・選定基準を解説](https://www.issoh.co.jp/tech/details/13578/)：フロントエンドでデータ取得中に描画を止めない、画面側の非同期描画の考え方をまとめています。
- [Celery（Python）とは：分散タスクキューの仕組みとブローカー選定・冪等性設計を解説](https://www.issoh.co.jp/tech/details/17293/)：Pythonでキューを使って非同期処理を組む具体実装。ブローカー選定と再試行・冪等性の設計まで扱っています。

---

出典: [非同期処理とは？同期処理との違いから実装方式まで実装者目線で解説](<https://www.issoh.co.jp/tech/details/13590/>)（株式会社一創）
