pako.js 完全指南:前端 zlib/gzip 压缩解压实战教程
在前端开发中,我们经常会遇到需要传输或存储大量数据的场景 - 大体积 JSON 上传、WebSocket 二进制流处理、本地离线缓存、Canvas 导出数据优化等。直接传输原始数据不仅浪费带宽,还可能因为请求体过大被网关拦截。这时候,一个轻量、高效、纯 JavaScript 实现的压缩库就显得尤为重要。
pako.js 正是这样一款工具。它是目前前端领域最主流的 zlib 压缩解决方案,完整实现了 deflate/inflate、zlib、gzip 三大标准格式,且无需任何原生依赖,浏览器和 Node.js 环境均可无缝运行。
一、pako.js 是什么
pako 是一个高性能的 zlib 压缩库,完全使用 JavaScript 编写,底层基于经典的 zlib C 库移植而来,不依赖 WASM,不依赖 Node.js 原生模块,是真正的跨平台纯 JS 实现。
它完整支持三种压缩格式:
- deflate / inflate :原始压缩算法,不带头部信息
- zlib 格式 :deflate 数据 + zlib 头尾校验,标准 zlib 流
- gzip 格式 :deflate 数据 + gzip 文件头/尾,兼容
.gz文件格式
这意味着 pako 压缩的数据可以直接被后端 Python、Java、Go、PHP 等语言的标准 zlib/gzip 库解析,反之亦然 - 前后端完全互通,不存在格式兼容问题。
典型应用场景
- 接口数据压缩 :大体积 JSON、表单数据压缩后上传,显著降低请求体大小
- WebSocket 二进制流 :实时通信场景下对消息进行 gzip 压缩,减少网络传输
- 本地存储扩容 :localStorage、IndexedDB 存储前压缩,变相提升存储容量
- 前端文件处理 :浏览器端直接读取和解压
.gz、.zlib格式文件 - 跨端统一逻辑 :Node.js 后端和浏览器前端共用一套压缩解压代码,降低维护成本
二、安装与引入
npm 安装
对于使用 Vite、Webpack、Rollup 等构建工具的现代前端项目,通过 npm 安装是最推荐的方式:
npm install pako安装完成后,使用 ES Module 或 CommonJS 方式引入:
// ES Module
import pako from 'pako'
// CommonJS
const pako = require('pako')CDN 直接引入
对于传统 HTML 项目或快速原型开发,可以直接通过 CDN 引入压缩后的版本:
<script src="https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako.min.js"></script>
<script>
// 挂载在全局 window.pako 上
console.log(pako.version)
</script>pako 2.x 是当前的稳定主版本,相比 1.x 进行了全面的 API 重构,接口设计更加规范统一,新项目建议直接使用 2.x 版本。
三、核心 API 详解
pako 的 API 设计非常简洁,核心只有压缩和解压两组函数,分别对应 zlib 和 gzip 两种格式。
3.1 deflate / inflate(zlib 格式)
pako.deflate() 用于压缩,输出标准 zlib 格式的二进制数据; pako.inflate() 用于解压。
// 压缩
const originalText = '这是一段需要被压缩的文本内容......'
const uint8Data = new TextEncoder().encode(originalText)
const compressed = pako.deflate(uint8Data)
// 返回值类型:Uint8Array
// 解压
const decompressed = pako.inflate(compressed)
const result = new TextDecoder().decode(decompressed)
console.log(result) // 输出原始文本注意 :pako 的输入和输出都是 Uint8Array 类型的二进制数据。如果需要处理字符串,必须先通过 TextEncoder 转为二进制,解压后再用 TextDecoder 转回字符串。这是初学者最容易踩的坑之一。
3.2 gzip / ungzip(gzip 格式)
如果需要生成标准的 .gz 文件格式,或者后端返回的是标准 gzip 数据,使用 pako.gzip() 和 pako.ungzip() :
// gzip 压缩
const source = new TextEncoder().encode('hello pako gzip')
const gzData = pako.gzip(source)
// gzip 解压
const rawData = pako.ungzip(gzData)
console.log(new TextDecoder().decode(rawData))gzip 格式和 zlib 格式的区别在于头部和尾部的元数据不同。gzip 包含文件名、修改时间等信息,是通用的文件压缩格式;zlib 格式更轻量,通常用于网络传输和内部数据交换。
3.3 配置选项
压缩函数支持传入第二个参数 options 来控制压缩行为:
const compressed = pako.deflate(data, {
level: 6, // 压缩等级 0-9,0=不压缩,9=最高压缩率,默认 6
windowBits: 15, // 窗口大小,默认 15(32KB 字典)
memLevel: 8, // 内存使用级别 1-9,默认 8
raw: false, // true=纯 deflate 无 zlib 头,适合自定义二进制协议
to: 'uint8' // 输出类型:uint8 / array,默认 uint8
})几个常用配置的说明:
- level :压缩等级是速度和压缩率的权衡。level=1 速度最快但压缩率低,level=9 压缩率最高但耗时更长,默认值 6 是一个比较均衡的选择。
- raw: true :只输出原始 deflate 数据块,不携带 zlib 头部和尾部校验信息。在 WebSocket 自定义二进制协议等场景中常用,可以节省几个字节的头部开销。但要注意,raw 模式压缩的数据只能用同样开启 raw 的 inflate 解压,格式必须严格对应。
四、流式处理:应对大文件
一次性将整个文件读入内存进行压缩,对于几十 MB 甚至上百 MB 的大文件来说,内存占用会非常高,浏览器端还可能造成主线程阻塞。
pako 提供了 Deflate 和 Inflate 两个类,支持分块流式压缩解压,可以边接收数据边处理,内存占用可控。
流式压缩
const deflator = new pako.Deflate({ level: 6 })
// 分块推入数据,第二个参数表示是否结束
deflator.push(chunk1, false) // 第一块,未结束
deflator.push(chunk2, false) // 第二块,未结束
deflator.push(chunk3, true) // 最后一块,标记结束
// 获取最终压缩结果
const compressedResult = deflator.result流式解压
const inflator = new pako.Inflate()
inflator.push(compressedChunk1, false)
inflator.push(compressedChunk2, false)
inflator.push(compressedChunk3, true)
const originalData = inflator.result流式处理特别适合配合 fetch 的 ReadableStream 、 FileReader 的分块读取、WebSocket 持续接收等场景。处理超大文件时,建议将压缩解压逻辑放到 Web Worker 中执行,避免阻塞主线程导致页面卡顿。
五、实战场景示例
5.1 JSON 数据压缩后 Base64 传输
很多时候接口只能接收字符串参数,不能直接传二进制。这时候可以先压缩再转 Base64 字符串,虽然 Base64 会带来约 33% 的体积膨胀,但压缩率足够高的话,最终体积仍然远小于原始 JSON。
/**
* 将 JS 对象压缩为 Base64 字符串
* @param {object} obj - 待压缩的对象
* @returns {string} Base64 编码的压缩数据
*/
function compressToBase64(obj) {
const jsonStr = JSON.stringify(obj)
const uint8 = new TextEncoder().encode(jsonStr)
const compressed = pako.gzip(uint8)
// Uint8Array 转 Base64
return btoa(String.fromCharCode(...compressed))
}
/**
* 将 Base64 字符串解压还原为 JS 对象
* @param {string} base64Str - Base64 编码的压缩数据
* @returns {object} 解压后的对象
*/
function decompressFromBase64(base64Str) {
const binaryStr = atob(base64Str)
const uint8 = new Uint8Array(
[...binaryStr].map(char => char.charCodeAt(0))
)
const raw = pako.ungzip(uint8)
return JSON.parse(new TextDecoder().decode(raw))
}
// 使用示例
const data = {
list: Array.from({ length: 1000 }, (_, i) => ({
id: i,
name: `item-${i}`,
value: Math.random()
}))
}
const base64 = compressToBase64(data)
console.log('压缩后长度:', base64.length)
const restored = decompressFromBase64(base64)
console.log('还原后条数:', restored.list.length)5.2 解压后端返回的 gzip 二进制数据
后端接口返回 gzip 压缩后的二进制数据,前端直接解压使用:
async function fetchCompressedData(url) {
const response = await fetch(url)
const arrayBuffer = await response.arrayBuffer()
const gzUint8 = new Uint8Array(arrayBuffer)
// 解压 gzip 数据
const rawUint8 = pako.ungzip(gzUint8)
const text = new TextDecoder().decode(rawUint8)
return JSON.parse(text)
}
// 调用
fetchCompressedData('/api/large-data.gz')
.then(data => {
console.log('数据加载完成:', data)
})5.3 前端生成 .gz 文件供下载
在浏览器端直接生成 gzip 压缩文件并触发下载:
function downloadGzFile(content, filename) {
const uint8 = new TextEncoder().encode(content)
const compressed = pako.gzip(uint8)
const blob = new Blob([compressed], { type: 'application/gzip' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename.endsWith('.gz') ? filename : `${filename}.gz`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
// 使用
downloadGzFile('大量文本内容......', 'data.txt')六、性能与注意事项
压缩率参考
对于文本类数据(JSON、HTML、CSS、JS 源码等),pako 的压缩率通常可以达到 60%~85% ,也就是压缩后体积只有原始的 15%~40%。具体压缩率取决于数据的重复度 - 重复内容越多,压缩效果越好。
对于已经压缩过的数据(如 JPG 图片、MP4 视频、zip 文件),再次压缩几乎没有效果,甚至可能因为增加了头部信息而导致体积略微变大,这类数据不建议再用 pako 压缩。
常见问题
- 格式不匹配导致解压失败 :gzip 格式压缩的数据只能用
ungzip解压,zlib 格式只能用inflate解压,raw deflate 必须两端都开启 raw 模式。格式混用会直接抛出错误,这是开发中最常见的问题。 - 字符串和二进制混淆 :pako 的输入输出都是
Uint8Array。直接传入字符串虽然部分情况下也能工作,但本质上是把每个字符的低 8 位当作字节处理,对于中文等多字节字符会产生严重错误。务必使用TextEncoder/TextDecoder进行转换。 - 主线程阻塞 :压缩解压是 CPU 密集型操作,处理 MB 级以上数据时,同步调用会阻塞主线程导致页面假死。生产环境建议将压缩逻辑放到 Web Worker 中异步执行。
- 浏览器兼容性 :pako 2.x 依赖
Uint8Array等现代 API,IE 等老旧浏览器需要引入相应的 polyfill 才能正常运行。
七、总结
pako.js 是前端处理数据压缩的首选工具,它的优势可以概括为以下几点:
- 纯 JavaScript 实现 ,无原生依赖,浏览器和 Node.js 全平台通用
- API 简洁直观 ,同步调用一行代码即可完成压缩解压
- 格式标准兼容 ,zlib/gzip 格式与后端各语言标准库完全互通
- 支持流式处理 ,大文件分块处理,内存占用可控
- 体积极小 ,压缩后仅十几 KB,对前端包体积影响微乎其微
无论是接口数据优化、WebSocket 消息压缩,还是本地存储扩容、前端文件处理,pako 都能提供稳定可靠的压缩能力。在数据量日益增长的前端应用中,掌握这样一个工具,能够有效提升应用的加载速度和用户体验。
发布评论
评论列表 0



