0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおける非同期設計戦略:Promise / async-await の原則、並列制御、キャンセル設計とエラーフロー

Posted at

概要

非同期とは「遅延する」ことではない。
それは**“待つことを制御し、失敗を受け入れ、構造として管理する”**ことに他ならない。

JavaScriptはイベント駆動・シングルスレッド。
非同期処理はアプリの応答性・性能・安全性に直結する。
本稿では、非同期処理を「動作」ではなく「設計」として扱うための戦略を解説する。


1. Promise と async/await の設計原則

✅ async/await は Promise をラップした構造

async function getData() {
  const res = await fetch('/api/data');
  return await res.json();
}
  • await“その場で中断”ではなく、“Promiseの完了を待って次へ”
  • ✅ 例外は try-catch で受ける → 明確な制御構造を持つ

2. 並列 vs 直列:Promise.all / for-await-of の使い分け

✅ 並列に投げる

const [a, b] = await Promise.all([fetchA(), fetchB()]);

✅ 直列で制御する

for (const url of urls) {
  const res = await fetch(url);
  handle(res);
}
  • ✅ 並列:全て同時に開始してまとめて取得
  • ✅ 直列:順番や依存がある場合に必須

3. 非同期エラーの捕捉と伝播

async function safeFetch(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error('Fetch failed');
    return await res.json();
  } catch (e) {
    return { ok: false, error: e.message };
  }
}
  • ✅ catch内で構造的なエラー返却を設計
  • ✅ 失敗時にも UI が破綻しない構造が必要

4. キャンセル可能な非同期:AbortController の利用

const controller = new AbortController();

fetch('/api', { signal: controller.signal });

setTimeout(() => controller.abort(), 3000);
  • 重複リクエストやコンポーネント破棄時のキャンセルに有効
  • ✅ UI操作と連動して非同期のキャンセル設計を導入すべき

5. UIと非同期の境界設計

❌ UI側で直接fetchを実行し状態が管理されない

button.onclick = () => {
  fetch('/api'); // 非管理な副作用
};

✅ UI → ロジック層(サービス) → fetch / 処理

async function onClick() {
  const data = await fetchUser();
  setUser(data);
}
  • 状態と副作用は分離して再現性とテスト性を確保

6. 非同期状態の「今」をUIで表現する

const [loading, setLoading] = useState(false);

const onClick = async () => {
  setLoading(true);
  try {
    const data = await fetchData();
    setData(data);
  } finally {
    setLoading(false);
  }
};
  • ✅ ローディング・成功・失敗を明示的に管理
  • ✅ 非同期の「今の状態」をUIで表現し、体験と同期する

設計判断フロー

① async/await を単に使うだけでなく、責務に応じた関数構成になっているか?

② 並列にできる処理を逐次で書いていないか?

③ エラーが握りつぶされていないか? → catch構造を明示

④ UI破棄時にも非同期処理が生きていないか? → AbortController活用

⑤ UIと非同期処理が分離されているか? → プレゼンテーション層とロジック層を区別

よくあるミスと対策

❌ 複数awaitを逐次で記述 → パフォーマンス劣化

→ ✅ Promise.all による並列化で高速化


❌ 非同期処理が途中でUIが破棄され、状態更新エラー

→ ✅ AbortControllerでキャンセル可能に設計 + cleanup設計


❌ UIが「何が起きているか」を示さずユーザーが混乱

→ ✅ loading, success, error を明示的にstate設計


結語

非同期とは「待つこと」ではない。
それは**“流れを制御し、今を把握し、未来を保証する”構造的な戦略**である。

  • 並列と直列を分け
  • エラーを受け入れて構造化し
  • UIと非同期の責務を分離し
  • 状態を「今」としてUIに同期する

JavaScriptにおける非同期設計とは、
“挙動ではなく構造として制御する、再現可能な戦略”である。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?