需求: 讓一個web項目可以提升 zip/rar壓縮包的解壓性能
一說到提升web端計算性能,在webAssembly面時以前,能聯想到的做法:
1,優化現有的js代碼
2,讓server端去計算,把計算結果告知client
以上2種做法都有一定的局限性,或者面對大部分需求下都不是最優解,webAssembly技術出現之后,就多了一個可行性的選項,不僅僅提升了性能,還對web端曾經一些無法規避的問題進行了擴展,比如客戶端加密。
個人理解,webAssembly就是用c/c++代碼以二進制文件的形式被瀏覽器加載並且調用,把原本只能用js寫的計算放到c/c++去計算,在特定情況下性能必然提升,而且因為瀏覽器加載的網頁資源文件對於用戶的透明性,即使是混淆,也無法做到完全加密,
而webAssembly支持的二進制文件,就徹底讓客戶端安全加密成為了可能。
先給出我在2020年6月做的一個測試報告:
webAssembly我的兼容性測試:
pc端:
不支持 IE 11.900.1862
不支持 win10 微信 最新版2.9.5.35
不支持 老版edge(基於IE) Microsoft Edge 44.18362.449.0
不支持 mac微信瀏覽器 2.3.30
支持:
新edge (基於chrome) 83.0.478.54
搜狗瀏覽器 10.0.0.32805
360安全瀏覽器 12.2.1246
360極速瀏覽器 12.0.1386
2345 10.9.0.20506
qq瀏覽器 10.5.3
chorme
firefox 77.0.1
mac safari
mac chrome
移動端:
ios
iphone7p 13.4.1
支持微信瀏覽器
支持自帶瀏覽器
iphone6s 13.5.1
支持微信瀏覽器
支持自帶瀏覽器
android
華為 mate (android 10)
支持微信瀏覽器
支持自帶瀏覽器
堅果pro2 (android 7.1.1)
支持微信瀏覽器
不支持 自帶瀏覽器
堅果M1L (android 6.0.1)
不支持 自帶瀏覽器
小米(android 10)
支持 微信瀏覽器
支持自帶瀏覽器
幾處踩坑:
【webAssembly wasm緩存踩坑 】
wasm模塊會強制緩存,比如需要被js調用的c里的一個方法打印了一句話,編譯並瀏覽器成功運行一次之后,改變剛才打印的那句話的內容,編譯,運行,發現居然還是老的內容,即使刪除了編譯出來的膠水文件.js和.wasm文件之后再編譯也不行。
網上有人建議一個辦法是改名字,直接修改c文件的名字,我是遇到了bug一開始沒意識到是這種緩存問題,把屏幕鎖定之后睡了一覺,起來之后再次運行發覺之前的bug居然沒有做任何處理就解決了,才意識到是緩存問題,
我的方法是關閉命令行再打開重新編譯一次
在瀏覽器環境和nodejs環境都做了測試,一些命令記錄:
啟動emcc命令: cd D:\webassembly\emsdk ./emsdk activate latest cd E:\xampp\htdocs\webassemblyTest #請輸入任意按鍵開始編譯wasm模塊... pause emcc c/ctest.c c/unzip.c lib/zip/zip.c -o out/unzip.js -O3 -s WASM=1 -s FORCE_FILESYSTEM=1 -s EXPORTED_FUNCTIONS='["_load_zip_data"]' -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap', 'addFunction', 'UTF8ToString', 'FS']" -s RESERVED_FUNCTION_POINTERS=1 -s MODULARIZE=1 -s ASSERTIONS=1 -s EXPORT_ES6=1 emcc .\c\ctest.c -o .\out\ctest.js -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" 下面這條起作用,針對我自己寫的helloworld js方法傳遞給c 讓c調用 nodejs環境下 可以成功的cmd配置: cd D:\webassembly\emsdk ./emsdk activate latest cd E:\xampp\htdocs\webassemblyTest #請輸入任意按鍵開始編譯wasm模塊... pause emcc .\c\ctest.c .\c\unzip.c .\lib\zip\zip.c -o .\out\ctest.js -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall','addFunction','removeFunction','UTF8ToString','FS']" -s RESERVED_FUNCTION_POINTERS=20 -s ALLOW_MEMORY_GROWTH=1 web環境下 可以成功的cmd配置: cd D:\webassembly\emsdk ./emsdk activate latest cd D:\xampp\htdocs\webassemblyTest #請輸入任意按鍵開始編譯wasm模塊... pause emcc .\c\ctest.c .\c\unzip.c .\lib\zip\zip.c -o .\out\ctest.js -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall','addFunction','removeFunction','UTF8ToString','FS']" -s RESERVED_FUNCTION_POINTERS=20 -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s ASSERTIONS=1 -s EXPORT_ES6=1 參數解釋: -s ALLOW_MEMORY_GROWTH=1 zip包文件數據過大時 加此參數 -s MODULARIZE=1 -s ASSERTIONS=1 -s EXPORT_ES6=1 允許web瀏覽器運行es6語法 經過測試,nodejs環境中: 1>js調用c方法 成功 2>js調用c方法並傳遞參數 成功 試過int ,string (如果直接通過 Module._function名字()的方式調用c的方法,傳遞給c的參數只能用int類型,如果要傳遞字符串,就得使用ccall) 3>js調用c方法並接受c方法返回的參數 成功 試過int ,string 4>js傳遞一個函數指針給c方法,c調用此函數指針 成功 5>js傳遞一個函數指針給c方法,c調用此函數指針並傳遞參數到js 成功 試過單參數(int) ,多參數(int ,int ),多參數不同類型 (const char* , int) 6>js fetch下載號的zip文件數據傳給c之后,c成功的解析好並回傳給了js 到此意味着在nodejs環境中,走通了讓nodejs端把下載好的zip文件讓c端去解壓並把返回解壓好的數據返回到nodejs端,
c端返回到js端的數據是unit8Array類型,如果zip文件不大的話,直接把js里的unit8array通過String.fromCharCode的方式轉換成字符串再JSON.parse轉換成json對象即可使用;
而大文件的話,在nodejs就會遇到內存溢出爆滿崩潰的問題,需要使用buffer,nodejs不支持blob而需要用buffer,web端看別人帖子是可以使用blob的方式,
web端直接使用上面說的String.fromCharCode的方式轉換成字符串再JSON.parse,可以成功
接下來嘗試網上帖子使用blob的方式,blob數據放入 URL.createObjectURL轉換格式嘗試失敗,改用FileReader讀取數據成功,花費4秒
參考資料: