在JavaScript應用程式開發中,我們時常使用AJAX傳送字串資料給伺服器或儲存在本機瀏覽器。當資料量過大時,可以考慮使用JavaScript字串壓縮函式庫lz-string來大幅度降低字串資料的體積。
In JavaScript application, we usually send string data to server by AJAX or store string in local web storage. If string data size is over the storage size limit, we could use a JavaScript string compress library “lz-string” to reduce stored string size.
適用情境 / Problem Context
壓縮字串資料量 / Compress String Size
最近我在研究改進KALS系統效率的方法。KALS在使用JavaScript計算瀏覽器上的標註位置時會耗費大量時間,如果能將運算結果以快取的形式儲存起來,那麼下次直接載入快取將可以節省大量的時間。
可是問題是瀏覽器端的儲存空間不大,cookie只有4K、Local Web Stroage(HTML5的新特性)只有5MB、Chrome Plugin不考慮。PHP的session一次最多可以存取128MB,但是要跟伺服器存取就很沒效率。
這時候就很適合使用lz-string壓縮字串,將資料量大幅縮小之後再儲存了。雖然就長期來看,如果運算結果變多了話,即使壓縮之後還是會有超過儲存上限的時候,不過那就是另外的議題了。
資料加密 / Encryption
另一種適用情況是加密資料。對網頁開發者或是初級駭客來說,有很多方式可以看到儲存在Cookie、Session、Local Strorage的資料,還有擷取與遠端伺服器溝通的資料(當然,這也包含了密碼)。藉由分析這些資料,我們可以輕易地了解遠端系統的資料架構。接下來就可以無視客戶端的操作介面與驗證程序,直接傳送我們想要的資料給伺服器。
以前在Facebook上的一款遊戲WarStorm就是採用明碼以XML跟伺服器傳送資料,讓許多玩家介入製作取代原本遊戲介面的機器人,降低手動遊玩所耗費的時間。這件事情讓我印象深刻,也對我後來進行程式設計的安全性上多了份考量。WarStorm後來將XML的資料全部加密,阻止玩家製作的機器人參與遊戲,不過卻造成遊玩人數大量流失,過不久就關閉了整個遊戲了。
話說回來,資料加密的方式其實還蠻多種的。除了單純到稱不上加密的escape()、encodeURI()、encodeURIComponent()自然不說,加密時常見的是md5演算法,而這個lz-stirng儘管效率較差,但是卻兼顧了壓縮與加密兩種特性。
總之,使用lz-string字串壓縮函式庫可以帶來的好處有兩個:
- 壓縮資料量
- 加密資料
缺點是需要耗費額外的運算時間,但這個缺點在可以節省資料傳輸與儲存等好處相較之下就顯得不是這麼重要了。
LZW演算法 / LZW Algorithm
LZW(Lempel-Ziv-Welch)是Abraham Lempel、Jacob Ziv與Terry Welch提出的一種無損數據壓縮演算法。它在1984年由Terry Welch改良Abraham Lempel與Jacob Ziv在1978年發表的LZ78的版本而來。這種演算法的設計著重在實現的速度,由於它並沒有對數據做任何分析,所以並不一定是最好的演算法(參考LZMA,LZ77)。
lz-string再根據JavaScript的使用情境作最佳化,最後完成了這個函式庫。在運作效率上,lz-string跟LZMA作了一些比較,在資料長短不同的測試案例下,壓縮率與運算時間皆有勝有負。不過我不是很在意這些細節就是,能用就好了XD
使用lz-string / lz-string Usage
使用方式很簡單:1. 引用lz-string;2. 使用compress壓縮資料;3. 使用decompress解壓縮資料,以下是引用lz-string的使用介紹:
- 下載lz-string的JavaScript檔案。作者的主要存放處是GitHub。我備份了一份最新版本的lz-string-1.3.3-min.js到Box.net。
- 在網頁中引用lz-string。注意以下紅字的部份,請寫入lz-string的正確網址
<script language="javascript" src="lz-string.js"></script>
- 接下來就能夠在JavaScript中使用lz-string韓式庫。主要用法是壓縮compress跟解壓縮decompress兩種:
var string = "This is my compression test.";
alert("Size of sample is: " + string.length);
var compressed = LZString.compress(string);
alert("Size of compressed sample is: " + compressed.length);
string = LZString.decompress(compressed);
alert("Sample is: " + string);
有興趣的人可以先玩玩看lz-string的線上展示頁面。
lz-string是針對localStorage最佳化,對於傳送資料給遠端伺服器來說就不是這麼合適。這時候要改用compressToBase64()與decompressFromBase64()。不過作者也提示了這兩種方法實際上並沒有進行壓縮,只是編碼而已。使用上可能還需要多多注意一下。
下一步 / Next
我嘗試在系統中使用lz-string壓縮資料,並驚嘆於lz-string的壓縮成果,所以才想要寫一篇來介紹一下這好用的壓縮資料庫。
在目前為止,我使用lz-string主要都是用於將資料儲存在localStorage。但是當資料量大到連lz-string壓縮之後都無法儲存的話,我就得轉個方向來思考了。下一步我可能會嘗試將快取資料儲存在伺服器端,並以lz-string壓縮資料以節省網路傳輸量。如果有什麼進度再來跟大家分享。
(more...)
Comments