利用webAssembly技术让提升浏览器解压性能
需求: 让一个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秒
参考资料: