JavaScript/ByteLengthQueuingStrategy

ByteLengthQueuingStrategy オブジェクト

概要

ByteLengthQueuingStrategy は JavaScript のストリーム API で使用される重要なクラスで、ストリームのバックプレッシャーを制御するために設計されています。このオブジェクトは、チャンクのバイトサイズに基づいてキューイング戦略を実装します。

基本的な使い方

ByteLengthQueuingStrategy オブジェクトは、チャンクのバイト長を計算し、ストリームのキューが特定のサイズ制限を超えないようにします。

const writableStream = new WritableStream({
  write(chunk) {
    // チャンクの処理
    return new Promise(resolve => setTimeout(resolve, 10));
  }
}, new ByteLengthQueuingStrategy({ highWaterMark: 1024 * 1024 }));

この例では、1MB(1024 * 1024バイト)の highWaterMark を持つストリームを作成しています。ストリームのバッファが1MBを超えると、書き込み操作は一時停止します。

コンストラクタ

ByteLengthQueuingStrategy のコンストラクタは、次のようなオプションオブジェクトを受け取ります:

new ByteLengthQueuingStrategy({ highWaterMark });

highWaterMark パラメータは必須で、キューに許容される最大バイト数を指定します。

メソッド

ByteLengthQueuingStrategy オブジェクトには以下のメソッドがあります:

// チャンクのサイズを計算するメソッド
const size = byteStrategy.size(chunk);

size() メソッドは、与えられたチャンクのバイト長を返します。デフォルトでは、チャンクの byteLength プロパティか length プロパティを使用します。

実際の使用例

ReadableStreamWritableStream の両方で ByteLengthQueuingStrategy を使用する例を見てみましょう:

// 大きなデータを生成する関数
function generateData(size) {
  return new Uint8Array(size).fill(65); // すべて 'A' で埋める
}

// ReadableStream の作成
const readableStream = new ReadableStream({
  start(controller) {
    // 開始時に1回だけ実行
    this.count = 0;
  },
  pull(controller) {
    // データが必要な時に呼び出される
    if (this.count < 10) {
      const chunk = generateData(100000); // 100KB のチャンク
      controller.enqueue(chunk);
      this.count++;
    } else {
      controller.close();
    }
  }
}, new ByteLengthQueuingStrategy({ highWaterMark: 200000 })); // 200KB

// WritableStream の作成
const writableStream = new WritableStream({
  write(chunk) {
    console.log(`${chunk.length} バイトのデータを受信`);
    // 書き込み処理のシミュレーション
    return new Promise(resolve => setTimeout(resolve, 100));
  }
}, new ByteLengthQueuingStrategy({ highWaterMark: 300000 })); // 300KB

// ストリームのパイピング
readableStream.pipeTo(writableStream)
  .then(() => console.log('転送完了'))
  .catch(err => console.error('エラーが発生しました:', err));

この例では、ReadableStream は 200KB の highWaterMark を持ち、WritableStream は 300KB の highWaterMark を持っています。ReadableStream は 100KB のチャンクを生成し、バックプレッシャーが適用されるまで(バッファが 200KB を超えるまで)チャンクを生成し続けます。

CountQueuingStrategy との比較

JavaScriptのストリームAPIには、ByteLengthQueuingStrategy に加えて CountQueuingStrategy もあります。これらの違いを以下の表で比較します:

特性 ByteLengthQueuingStrategy CountQueuingStrategy
サイズ計算 チャンクのバイト長を使用 すべてのチャンクを1として計算
用途 バイナリデータやサイズが可変のデータ 均一なサイズのオブジェクト
精度 メモリ使用量をより正確に制御 チャンク数のみを制御
デフォルトの size() byteLength または length を返す 常に 1 を返す

カスタムキューイング戦略

ByteLengthQueuingStrategy が要件に合わない場合は、独自のキューイング戦略を実装することも可能です:

const myStrategy = {
  highWaterMark: 1024,
  size(chunk) {
    // JSON文字列のバイト長を計算する例
    return new TextEncoder().encode(JSON.stringify(chunk)).length;
  }
};

const writableStream = new WritableStream({
  write(chunk) {
    console.log('チャンク処理中');
    return Promise.resolve();
  }
}, myStrategy);

この例では、JSON オブジェクトのバイト長を計算するカスタム戦略を実装しています。

注意事項

ByteLengthQueuingStrategy を使用する際の重要な考慮事項:

  1. バイナリデータ(TypedArrayArrayBuffer など)を扱う場合に特に有用です。
  2. テキストデータの場合、byteLength が常に正確なバイト数を表すとは限りません。UTF-8 エンコーディングではマルチバイト文字が存在します。
  3. ブラウザによって実装が異なる場合があるため、クロスブラウザ互換性をテストすることが重要です。

効率的なストリーム処理のためには、データの性質に応じて適切な highWaterMark 値を設定することが重要です。値が小さすぎるとパフォーマンスが低下し、大きすぎるとメモリ使用量が増加します。

カテゴリ:JavaScript
カテゴリ:JavaScript