サーバーに大きなデータを送信するとき・・・
- できるだけデータ量を小さくしたい
- サーバーに負荷をかけたくない
そういうときはクライアント側(JS側)で圧縮したいときがあります。
僕自身そういう場面があったので、
ここでは JavaScriptで gzip圧縮・展開できる zlib.js というライブラリ を使ってみました。
その忘備録。これから非サーバー側からgzip圧縮したい人の役に立つかもです。
このページの目次
今回は zlib.js というライブラリを導入してみた
今回使ったのは zlib.js というライブラリ
このライブラリは色んな圧縮形式に対応しているようで・・・
- ZLIB(RFC1950),
- DEFLATE(RFC1951)
- GZIP(RFC1952)
- PKZIP(ZIP)
これだけの形式をシンプルなコードで圧縮・展開できるみたいです。
便利そうだったので、GitHubからダウンロードしてみました。
▼ zlib.jsのダウンロードページ(GitHub)
このページから zip をDLし、展開したディレクトリの bin 内にあるファイルを必要な場所に貼り付けするだけで使えると書いてあります。
今回は gzip なので、次の2つをコピペしました。
- gzip.min.js
- gunzip.min.js
この2つさえあれば、他に依存ライブラリなども必要ありません。
ためしに文字列(JSON)を圧縮・展開してみた
まず試しに文字列(JSON)を展開・圧縮することに
GitHubによると、Gzipは次のように扱えるらしいです。
▼ データを圧縮するお手本コード例
1 2 3 |
// plain = Array.<number> or Uint8Array var gzip = new Zlib.Gzip(plain); var compressed = gzip.compress(); |
▼ データを展開するお手本コード例
1 2 3 |
// compressed = Array.<number> or Uint8Array var gunzip = new Zlib.Gunzip(compressed); var plain = gunzip.decompress(); |
ん...? Array.<number> or Uint8Array ...?
なるほど、どうやら文字列でもバイナリに一旦変換しないとダメらしいです。
ということで、まずは 文字列 <=> Uint8Array と変換できる関数 を作ってみます。
その関数のコードがコチラ
▼ 文字列 => Uint8Arary に変換する関数
1 2 3 4 5 6 7 8 9 |
/// 文字列をUint8Arrayに変換 function strToUint8Arr(str) { var str = btoa(unescape(encodeURIComponent(str))), charList = str.split(''), uintArray = []; for (var i = 0; i < charList.length; i++) { uintArray.push(charList[i].charCodeAt(0)); } return new Uint8Array(uintArray); } |
▼ Uint8Array => 文字列に変換する関数
1 2 3 4 5 6 |
/// Uint8Arrayを文字列に変換 function uint8ArrToStr(uint8Arr) { var encodedStr = String.fromCharCode.apply(null, uint8Arr), decodedStr = decodeURIComponent(escape(atob(encodedStr))); return decodedStr; } |
意外と 文字列 <=> Uint8Array の変換は面倒っぽい・・・
それから今回はテキストの場合だけど、画像とか音声とかのバイナリデータでも Uint8Array に変換する処理を書かなないとダメです。
そしてこの関数とzlib.jsを使って JSONを圧縮&展開するコード を書いてみます。
▼ 実際に書いてみたコードがコレ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var json = '【圧縮したいJSON文字列】'; /// 必ず Uint8Array に変換すること var jsonPlain = strToUint8Arr(json); /// そしたらJSONをGzipに圧縮 var gzip = new Zlib.Gzip(jsonPlain); var compressed = gzip.compress(); /// そして圧縮データを展開 var gunzip = new Zlib.Gunzip(compressed); var jsonPlain = gunzip.decompress(); /// Uint8Array なので文字列に戻す必要あり! var json = uint8ArrToStr(jsonPlain); |
これで一応やりたいことはできました。
データもしっかり圧縮されたし、展開したら元のデータにちゃんと戻ってます。
ちなみに zlib.js での文字列(JSON)の圧縮率を計測
まあデータの種類によるから一概に言えないけど。
気になったので 文字列の圧縮率 を確かめてみました。
今回、検証に使ったのは次みたいなJSON
1 |
{"menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, {"id": "OpenNew", "label": "Open New"}, null, {"id": "ZoomIn", "label": "Zoom In"}, {"id": "ZoomOut", "label": "Zoom Out"}, {"id": "OriginalView", "label": "Original View"}, null, {"id": "Quality"}, {"id": "Pause"}, {"id": "Mute"}, null, {"id": "Find", "label": "Find..."}, {"id": "FindAgain", "label": "Find Again"}, {"id": "Copy"}, {"id": "CopyAgain", "label": "Copy Again"}, {"id": "CopySVG", "label": "Copy SVG"}, {"id": "ViewSVG", "label": "View SVG"}, {"id": "ViewSource", "label": "View Source"}, {"id": "SaveAs", "label": "Save As"}, null, {"id": "Help"}, {"id": "About", "label": "About Adobe CVG Viewer..."} ]}} |
JSONみたいに、同じ文字列( " とか : )が含まれるのは圧縮率が高くなりそう
ということで圧縮する前と圧縮した後の結果がコチラ
- 圧縮前 : 719bytes
元のJSONはこれだけの大きさ。これを圧縮すると。。。
- 圧縮後 : 418bytes
なんと圧縮率は 41.86% という結果に・・・
まあJSONは冗長なデータが多いので、このくらいが妥当
もしもっと冗長で繰り返しが多いなら、さらに圧縮率は高くなるはずです。
GZip圧縮するなら zlib.js が超便利
ということで zlib.js の使い方についてでした。
ブラウザ側でデータ圧縮・展開が必要なときに使っていきたいです。