- プログレッシブJPEGのように、JSONデータも不完全な状態で先に送信し、クライアントが徐々に内容全体を活用できる方式を紹介
- 既存のJSONパース方式には、データ全体を完全に受信するまで何も処理できないという非効率性の問題がある
- Breadth-first方式でデータを複数のチャンク(部分)に分け、まだ準備できていない部分はPromiseで表し、準備できしだい段階的に埋めていくことで、クライアントは未完成のデータも活用できる
- この概念は**React Server Components(RSC)**の中核的な革新であり、
<Suspense>を通じて意図した段階的なローディング状態を制御する
- データストリーミングと意図的なUIローディングフローを分離することで、より柔軟なユーザー体験を提供できる
プログレッシブJPEGとProgressive JSONのアイデア
- プログレッシブJPEGは、画像を上から下へ一度に読み込む代わりに、まず全体をぼんやり表示し、徐々に鮮明になる方式
- これと同様に、JSON転送にもプログレッシブ方式を適用することで、全体が完成するまで待たずに一部のデータを即座に使うことができる
- 例となるJSONデータ構造では、通常の方式では最後のバイトまで受信しないとパースできない
- そのためクライアントは、サーバーの遅い部分(例: 遅いDBからcommentsを読み込む処理)まですべて送信されるのを待つ必要があり、これは現在の標準として非常に非効率である
ストリーミングJSONパーサーの限界
- ストリーミングJSONパーサーを導入すると、不完全な(途中段階の)データオブジェクトツリーを生成できる
- しかし、各オブジェクトのフィールド(例: footer、複数のcomment一覧など)が一部しか届いていない場合、型が一致せず、完成済みかどうかも把握しづらいため、活用しにくいという問題が生じる
- HTMLのストリーミングレンダリングと同様に、順番どおりにストリーム処理すると、ひとつの遅い部分が全体の結果を遅らせるという問題も同じように起こる
- これが一般にストリーミングJSONがあまり使われない理由である
Progressive JSON構造の提案
- 従来の深さ優先ストリーミング(つまり、ツリー構造の下位まで内部をたどって送信する方式)ではなく、Breadth-first(幅優先)方式を導入
- 最上位オブジェクトだけを先に送信し、下位の値はPromiseのようなプレースホルダーとして置いておき、準備できしだいそれぞれを個別のチャンクとして埋めていく
- たとえばサーバーは、非同期のデータ読み込みが完了するたびに対応するチャンクを送信し、クライアントは準備できた分だけ利用できる
- **非同期なデータ受信(早期ロード)**が可能になり、複数の遅い部分の処理がすべて終わるまで全体を待つ必要がなくなる
- クライアントをチャンク単位の非順次受信および部分的な順次受信に強く設計すれば、サーバーはさまざまなチャンク分割戦略を柔軟に適用できる
InliningとOutlining: 効率的なデータ転送
- プログレッシブJSONストリーミング形式では、再利用されるオブジェクト(例: 同じuserInfoを複数箇所から参照)も重複保存せず、ひとつのチャンクとして切り出して各場所から同じ参照を共有できる
- 遅い部分だけを分離してプレースホルダーとして送り、それ以外はすぐ埋めることで効率的なデータストリームを実現する
- 同じオブジェクトが何度も現れる場合でも、一度だけ送信して再利用(Outlining)できる
- この方式により、**循環参照(オブジェクトが自分自身を参照する構造)**も通常のJSONのように扱いに困らず、チャンク間の間接参照構造として自然にシリアライズできる
React Server Components(RSC)のプログレッシブストリーミング実装
- 実際のReact Server Componentsは、プログレッシブJSONストリーミングモデルを適用した代表例である
- サーバーは外部データ(例: Post、Comments)を非同期に読み込む構造を使う
- クライアントでは**まだ到着していない部分をPromiseとして扱い、**準備できた順にUIを段階的にレンダリングする
- Reactの
<Suspense>で意図的なローディング状態を設定
- ユーザー体験上不要な画面のジャンプを防ぐため、Promise状態(穴)をそのまま見せるのではなく、
<Suspense>のfallbackで段階的なローディング演出が可能
- データが素早く到着しても、実際のUIは設計された段階に合わせて段階的に表示されるよう、開発者が制御できる
要約と示唆
- React Server Componentsの中核的な革新は、コンポーネントツリーのpropsを外側から段階的にストリーミングする方式にある
- したがって、サーバーがすべてのデータを完全に準備するまで待つ必要はなく、主要な部分から少しずつ見せながら、ローディング待機状態も細かく制御できる
- ストリーミングそのものだけでなく、それを活用するプログラミングモデル(Reactの
<Suspense>)のような構造的支援もあわせて必要である
- これにより、遅いデータの一部分が全体を遅らせるといった従来の転送方式のボトルネックを緩和できる
1件のコメント
Hacker Newsの意見