🔥
CompressionStream でブラウザで gzip 圧縮する
モダンなブラウザは JS API として gzip や deflate が使えます。
昔から Chrome に搭載してるのは知ってたんですが、今見たらだいたい搭載してました。
わかってる人向けに言うと、バンドルサイズ大きめの JS実装の pako や zlib.js が不要になって、ブラウザネイティブの(たぶんHTTP上のgzip展開と同等の)高速な実装が使えます。
// impl
const encoder = new TextEncoder();
const decoder = new TextDecoder();
export async function compress(str: string): Promise<ArrayBuffer> {
const cs = new CompressionStream("gzip");
const buf = encoder.encode(str);
const stream = new Response(buf).body!.pipeThrough(cs);
return new Response(stream).arrayBuffer();
}
export async function decompress(buffer: ArrayBuffer): Promise<string> {
const ds = new DecompressionStream("gzip");
const decompressedStream = new Blob([buffer]).stream().pipeThrough(ds);
const buf = await new Response(decompressedStream).arrayBuffer();
return decoder.decode(buf);
}
// usage
const json = { a: 1 };
const str = JSON.stringify(json);
const compressed = await compress(str);
const restored = await decompress(compressed);
console.assert(str === restored);
ブラウザ上のJSで gzip できると何が嬉しいかと言うと、なんかバイナリデータを保存する必要がある時に ArrayBuffer を gzip したやつを indexeddb の blob にして突っ込むと、ストレージサイズかなり節約できます。
なんでストレージサイズを小さく保ちたいかと言うと、ブラウザの気分次第ではあるんですが基本的にはストレージ使用量大きいほど消されやすいというのがあります。
サイズが大きくてアクセス頻度が低いほど消されやすい印象。
あとは、S3 や duckdb, parquet, arrow 辺りのAPIと直接喋ったりする時にも、なんか使った記憶があります。
Discussion