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?

Chrome 151 で追加された textStream() で、テキストストリーミングがシンプルになった

0
Last updated at Posted at 2026-07-07

はじめに

Chrome 151 で RequestResponseBlobtextStream() メソッドが追加されました。

これまでバイトストリームをテキストとして読み取るには TextDecoderStream を経由するパイプ処理が必要でしたが、
textStream() を使うとその手順をそのままショートカットできます。
LLM のストリーミングレスポンスや大きなテキストファイルの逐次処理など、
テキストをストリームで扱う場面で役立ちます。

従来の書き方との比較

従来:TextDecoderStream を経由する

const response = await fetch('/api/stream');

const reader = response.body
  .pipeThrough(new TextDecoderStream())
  .getReader();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(value); // デコード済みテキスト
}

response.body はバイト列(Uint8Array)を流す ReadableStream のため
、テキストとして読み取るには TextDecoderStream でデコードする必要がありました。

Chrome 151 以降:textStream() を使う

const response = await fetch('/api/stream');

const reader = response.textStream().getReader();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(value); // デコード済みテキスト
}

textStream() は「バイトストリームを TextDecoderStream にパイプしたもの」と等価な ReadableStream<string> を返します。
pipeThrough(new TextDecoderStream()) がそのまま省略できます。

for await...of と組み合わせる

ReadableStream は非同期イテラブルなので、for await...of と組み合わせるとより簡潔に書けます。

const response = await fetch('/api/stream');

for await (const chunk of response.textStream()) {
  process(chunk);
}

実用例:LLM のストリーミングレスポンスを画面に表示

チャット UI などで LLM のレスポンスをリアルタイムに表示するユースケースに特に相性が良いです。

async function streamChat(message) {
  const response = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message }),
  });

  const output = document.getElementById('output');

  for await (const chunk of response.textStream()) {
    output.textContent += chunk;
  }
}

従来は TextDecoderStreamgetReader() を組み合わせるボイラープレートが必要だったものが、textStream() + for await...of で完結します。

Blob でも使える

Response だけでなく Blob にも同じ textStream() が追加されています。

const blob = new Blob(
  ['1行目\n2行目\n3行目\n'],
  { type: 'text/plain' }
);

for await (const chunk of blob.textStream()) {
  console.log(chunk);
}

ファイル選択(<input type="file">)で取得した File オブジェクトは Blob のサブクラスなので、そのまま textStream() が使えます。

input.addEventListener('change', async (e) => {
  const file = e.target.files[0];

  for await (const chunk of file.textStream()) {
    processLine(chunk);
  }
});

まとめ

textStream() は小さな追加ですが、テキストストリームを扱うたびに書いていた pipeThrough(new TextDecoderStream()) のボイラープレートを一掃できます。
LLM レスポンスのストリーミング表示や大きなテキストファイルの逐次処理など、ストリームでテキストを扱う機会が増えている今、覚えておきたい API のひとつです。

参考


最後まで読んでくださってありがとうございます!

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

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?