◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-07-24上級

同じ通信が同時に何本も飛ぶのを1本に束ねる — 参照カウント付きシングルフライト層の設計

起動直後に同じ API へ何本ものリクエストが同時に飛ぶ多重フェッチを、進行中の Promise を共有して1本に束ねる設計です。束ねる範囲を決めるキーの組み立て方、失敗した Promise を配り続けてしまう罠、呼び出し側の中断が全体を巻き込む罠、そして束ね率を数えて回帰を止めるテストまで、参照カウント付きシングルフライト層の実装を実測の通信ログとともに残します。

Rork595React Native240API6パフォーマンス33アーキテクチャ22

✦ プレミアム記事

夜、リリース直後の壁紙アプリをネットワークインスペクタにつないで開いた瞬間、同じ URL の行が続けざまに並びました。/me/entitlements が、わずか 200ms ほどのあいだに 4 本。どれも中身は同じで、返ってくる JSON も同じでした。

胸の奥がざわつきました。無駄な通信が 4 倍になるだけならまだしも、同じ端末で 3 本の 401 が重なった直後、ユーザーの何人かが不意にログアウトさせられていたのです。トークンの期限切れに対して 3 本が同時に更新をかけ、後から完了した更新が先に発行されたトークンを無効化していました。

原因は 1 画面ではありませんでした。ホーム、お気に入りバッジ、課金ゲート — 別々のコンポーネントが、それぞれ「自分が必要だから」と同じ取得を独立に走らせていただけです。誰も、隣がすでに同じものを取りにいっていることを知りませんでした。

取り上げたいのは、この「同時多発する同一リクエスト」を、進行中の 1 本に束ねる設計です。個人開発で 6 本のアプリを同じ通信基盤で回している中で、あの夜のあとに実際へ入れて運用しているコードをもとにしています。難しい仕組みではありません。けれど、素直に書くと必ず踏む罠が二つあり、そこを抜けて初めて実用になります。

なぜ同じリクエストが同時に飛ぶのか

React Native のアプリでは、画面がマウントされた瞬間に各コンポーネントの useEffect が走ります。同じデータを必要とする複数のコンポーネントが同時に現れると、それぞれが独立に fetch を発行します。

Rork が生成する取得コードは、たいていコンポーネントの内側で完結しています。次のような形です。

function useEntitlements() {
  const [data, setData] = useState<Entitlements | null>(null);
  useEffect(() => {
    fetch(`${API}/me/entitlements`, {
      headers: { Authorization: `Bearer ${token}` },
    })
      .then((r) => r.json())
      .then(setData);
  }, []);
  return data;
}

このフックを 3 つのコンポーネントが呼べば、fetch は 3 本走ります。各フックは自分のローカル状態しか見ておらず、「同じ取得がすでに進行中かどうか」を共有する場所がどこにもありません。

キャッシュを挟めばいいのでは、と最初は考えました。けれど、初回の起動直後はキャッシュが空です。全員がほぼ同時に「キャッシュが無い」と判断し、そろって取得に走ります。キャッシュが埋まるのは全員が投げ終えた後で、間に合いません。守るべきは「結果の保存」ではなく、「進行中の 1 本を共有すること」でした。

シングルフライトの核 — 進行中の Promise を共有する

やることは一つです。あるキーに対する取得がすでに進行中なら、新しい fetch を投げず、進行中の Promise をそのまま返します。これをシングルフライト、あるいはリクエストのコアレッシング(束ねること)と呼びます。

最小の形はこれだけです。

const inflight = new Map<string, Promise<unknown>>();
 
function coalesce<T>(key: string, run: () => Promise<T>): Promise<T> {
  const existing = inflight.get(key);
  if (existing) return existing as Promise<T>;
 
  const promise = run();
  inflight.set(key, promise as Promise<unknown>);
  return promise;
}

キーは「何を取りにいくか」を一意に表す文字列にします。GET /me/entitlements のように、メソッドとパスを組み合わせるのが分かりやすい形です。同じキーで 4 回呼ばれても、run() が実際に走るのは最初の 1 回だけになります。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦起動時に同一 GET が多重に飛ぶのを、進行中の Promise を共有して1本へ束ねるシングルフライト層の実装
✦失敗した Promise が次回以降の呼び出しにも配られ続ける罠と、settle 時に必ず消す書き方
✦呼び出し側1つの中断が共有リクエスト全体を巻き込まないための、参照カウント付き AbortController
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 開発ツール2026-08-01
実験の割り当てが同じ端末に偏る — 100万件のIDで確かめたハッシュ選定と salt の位置
端末側で実験の変種を決める割り当てが、実験を2本並べた途端に同じ端末へ集中しました。100万件のIDで4つのハッシュを測り、原因がハッシュの一様性ではなく salt の連結位置にあったこと、そして採用した実装までを実測値とともに残します。
⬡ 開発ツール2026-07-24
アプリの設定値を三層で解決する — 既定・ユーザー・リモートを境界付きにマージするレイヤー設計
既定値・ユーザー設定・リモート設定をひとつの型安全なレイヤーでマージする設計です。壊れたリモート値でもアプリが崩れないよう、キーごとに上書きの強さを変え、境界クランプと検証を通す実装を、実際の事故から起こしたコードで解説します。
⬡ 開発ツール2026-05-02
FlatList でカクつき始めたら読む — Rork アプリを FlashList v2 で快適にする実装手順
Rork で生成したアプリの長いリストが重くなったとき、FlashList v2 へ移行することでスクロールが大幅に滑らかになります。estimatedItemSize が不要になった v2 の思想を踏まえた、現実的な移行手順を解説します。