CompressionStream:瀏覽器內建的 gzip
Streams API 的一員,讓前端不用再引 pako 之類的 JS 壓縮庫(幾十 KB,純 JS 也慢)。實作在瀏覽器的 C++ 層(zlib),快很多而且不佔 bundle。
readableStream
.pipeThrough(new CompressionStream('gzip')) // 壓縮
.pipeThrough(new DecompressionStream('gzip')); // 解壓支援 'gzip' / 'deflate' / 'deflate-raw'。
手動切塊是為了真實的進度回報
即使資料已經全在記憶體裡、可以整塊餵進去,仍然值得自己切成小塊:ReadableStream 的 pull() 只有在下游真的消化完前一塊時才會被呼叫,所以 onProgress 反映的是實際的壓縮進度,而不是「已經丟進 buffer 的量」。這是 pull-based 才有的性質。
const stream = chunkedSource(buffer, onProgress).pipeThrough(new CompressionStream('gzip'));
return new Response(stream).blob();解壓前先檢查 magic byte
如果 server 回應帶了 Content-Encoding: gzip,瀏覽器會自己先解壓,JS 拿到的 Blob 已經是解壓後的;這時再跑一次 DecompressionStream 會丟 incorrect header check。檢查前兩個 byte(0x1f 0x8b)就知道到底解過沒有。
支援度:這通常是這類方案裡最新的相依
Chrome 80(2020)/Safari 16.4(2023-03)/Firefox 113(2023-05)——比 WebAssembly(2017 三大瀏覽器全數落地)晚了六年。所以「這功能需要很新的瀏覽器」的原因往往不是 WASM,而是它。
⚠️ 沒有 feature detection 時,不支援的瀏覽器是當場丟 ReferenceError: CompressionStream is not defined,不是慢慢壞。專案若沒有 browserslist / babel targets 把支援矩陣固定下來,「我們的使用者一定有」就只是一句沒有強制力的註解。