問題 今天組長跟我們討論了個問題,說是文章存儲占用有點大,消耗寬頻流量費,讓我看看能不能找個方法解決一下(文章存儲的是html字元串)。第一反應是沒什麼頭緒,能想到的就是將相同的字元串替換成一個標識之類的,小程式再通過標識替換回原本的字元(感覺就不是很靠譜...)。 後來發現真的不靠譜,首先每篇文章 ...
問題
今天組長跟我們討論了個問題,說是文章存儲占用有點大,消耗寬頻流量費,讓我看看能不能找個方法解決一下(文章存儲的是html字元串)。第一反應是沒什麼頭緒,能想到的就是將相同的字元串替換成一個標識之類的,小程式再通過標識替換回原本的字元(感覺就不是很靠譜...)。
後來發現真的不靠譜,首先每篇文章樣式可能都不一樣,需要很多對應的字典,即使是這樣大概預估了下,也減少不過10多k左右。唉,還是面向百度編程吧,看看有沒有什麼別人寫好的模塊可以用一下。
然後就找到了pako.js,具體實現是本地gzip壓縮成base64。我在pc端稍微測試了下,原本150k左右的文章,能夠壓縮到14k,壓縮率90%。嗯,不錯,開始搞一下。可後面的路並沒有我想的那麼順暢...
準備工作
要是用第三方模塊,肯定需要npm包管理工具是吧。npm init,然後npm i pako,一頓操作,引入文件測試。哦豁,報錯找不到這個包。因為在公司一直都是用的原生小程式語法開發,沒使用過三方模塊,所以這方面一直沒去瞭解,還以為和web端的差不多。沒事嘛,面向百度編程。百度了一堆亂七八糟的,都沒什麼作用,還是乖乖的看官方文檔吧,沒想到幾分鐘的事就解決了(有時候還是文檔靠譜)。
- npm init 創建package.json
- npm i pako
- 開發者工具左上角 -> 工具 -> 構建npm
- 開發者工具右上角 -> 勾選使用npm模塊
- 文件中引入模塊使用
附上文檔鏈接:https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html
開始踩坑
資料庫存儲的文章已經壓縮過,現在要做的就是在小程式解壓縮還原成html字元串並渲染出來。
壓縮文章代碼:
1 function zip(str){
2 let binaryString = pako.gzip(encodeURIComponent(str), { to: 'string' }),
3 res = btoa(binaryString);
4 return res
5 }
封裝一個解壓縮的函數(裡面用到的方法都是pako寫好的,直接調用),代碼:
1 var pako = require('pako');
2
3 page({
4 ...
5 unzip(b64Data){
6 let strData = atob(b64Data),
7 charData = strData.split('').map(function(x){return x.charCodeAt(0);}),
8 binData = new Uint8Array(charData),
9 data = pako.inflate(binData);
10 strData = String.fromCharCode.apply(null, new Uint16Array(data));
11 return decodeURIComponent(strData)
12 }
13 })
然後將介面拿到的文章傳入到 unzip 中就可以解壓出來了。當然這隻是我預期的結果(因為web端這樣的操作確實可行)
真機調試後小程式報錯,找不到atob
原因是pako方法中使用到window.atob,而小程式不支持這個方法,所以導致報錯。
解決方法:引入atob的polyfill,就是在小程式實現一個atob方法
atob polyfill 下載地址:https://github.com/davidchambers/Base64.js ( 該polyfill實現了atob和btoa)
1 const polyfill = require('../../utils/base64')
2 const {atob, btoa} = polyfill;
引入atob後,再跑一遍真機測試,誒,舒服了,完美的展示出來,而且響應速度和原本的沒有什麼差別
然後我以為完成任務了,在測試一篇稍微大點的文章時(260k左右),小程式再次報錯
而且居然是調用棧記憶體溢出。wtf?!初步我還以為自己邏輯寫錯,導致出現遞歸死迴圈之類的。檢查幾遍後,並沒有發現錯誤。只能再次求助百度...
得到的原因是因為數據量過大,導致在進行 String.fromCharCode.apply(null, new Uint16Array(data)) 時,出現棧記憶體溢出的問題,用以下的函數代替這步即可:
1 function handleCodePoints(array) {
2 var CHUNK_SIZE = 0x8000; // arbitrary number here, not too small, not too big
3 var index = 0;
4 var length = array.length;
5 var result = '';
6 var slice;
7 var arr = [];
8 for (var i = 0, _i = array.length; i < _i; i++) {
9 arr[i] = array[i];
10 }
11 while (index < length) {
12 slice = arr.slice(index, Math.min(index + CHUNK_SIZE, length)); // `Math.min` is not really necessary here I think
13 result += String.fromCharCode.apply(null, slice);
14 index += CHUNK_SIZE;
15 }
16 return result;
17 }
寫在最後
後面測試過程中並未出現其他問題,測試了更大的數據量後也沒什麼問題。至此,我在小程式使用pako.js之路告一段落。之後如果還有存在問題,我會繼續更新這篇文章。若你在使用過程中發現其他問題,請告訴我。