最近在破解网站验证码的时候,图像识别速度上遇到一点瓶颈。按照我如今的代码,从获取到验证码图片到输出正确验证码字符串须要等待3秒的时间,可是3秒以后破解完黄花菜都凉了,因此我想有没有什么方法让程序执行的快一点,最后目光聚焦在了Webassembly,因此入门学习了一下Webassembly。javascript
Webassembly顾名思义web+assembly,web版的汇编语言,其实它并非一种语言,它只是为高级语言(诸如C、C++和Java)提供一个高效的编译目标。之因此和汇编能扯上关系,是由于它是接近计算机机器码的二进制字节码,而且能够在现代浏览器直接运行。html
众所周知javascript是被十天设计出来的弱类型语言,整个web的性能优化史就是一个js的填坑史,JIT引擎让js的执行速度快了10倍,为了弥补JIT引擎的缺点,又出现了asm.js、TypeScript等js子集,至此web性能已经很高,可是人类的欲望是没有止境的,浏览器厂商仍是再想怎么可让web速度更快,因而Webassembly横空出世, 相比js,Webassembly体积更小、加载更快,兼容性强,执行速度快,这也是我所须要的。前端
使用一个新技术的时候咱们首先得看一下它在浏览器上的兼容性。进入Webassembly的官方网站,在导航条下方醒目的展现着“Webassembly 1.0 has shipped in 4 major browser engines. ”。代表现代浏览器对Webassembly的支持很是友好。java
再看一下具体浏览器支持状况:node
在 package.json 的依赖加入 AssemblyScript 模块的 Github 来源。git
"devDependencies": {
"assemblyscript": "github:assemblyscript/assemblyscript"
}
复制代码
执行cnpm install,等待安装完成用asc来看一下是否安装成功。若是显示asc的使用命令行,则说明安装成功。github
export function sqart (a: number): number {
return a * a;
}
复制代码
"scripts": {
"build": "npm run build:optimized",
"build:optimized": "asc src/index.ts -t dist/module.optimized.wat -b dist/module.optimized.wasm --optimize"
}
复制代码
--optimize 表明编译时须要优化,在项目根目录执行npm run build命令开始编译,最终在dist目录下生成module.optimized.wasm和module.optimized.wat两个文件,它们分别是WebAssembly字节码文件和WebAssembly文本文件。编译完成的目录结构如图所示:web
const fs = require("fs");
const path = require('path');
const env = {
memoryBase: 0,
tableBase: 0,
memory: new WebAssembly.Memory({
initial: 256
}),
table: new WebAssembly.Table({
initial: 2,
element: 'anyfunc'
}),
abort: () => {throw 'abort';}
}
const wasm = new WebAssembly.Module(
fs.readFileSync(path.join(__dirname, "..", "/dist/module.optimized.wasm"))
);
const mod = new WebAssembly.Instance(wasm, {env: env})
module.exports = mod.exports;
复制代码
而后在index.js里使用封装好的wasm模块,npm
var myModule = require("./module.js");
console.log("3 sqart is: ", myModule.sqart(3));
复制代码
在根目录下运行node ./nodejs/index.js,输出下面结果:编程
在index.js里引入wasm模块,代码以下:
const env = {
memoryBase: 0,
tableBase: 0,
memory: new WebAssembly.Memory({
initial: 256
}),
table: new WebAssembly.Table({
initial: 2,
element: 'anyfunc'
}),
abort: () => {
throw 'abort';
}
}
/**
* 连接wasm和js的胶水代码
* @param {String} path wasm 文件路径
*/
function loadWebAssembly(path) {
return fetch(path)
.then(response => response.arrayBuffer())
.then(buffer => WebAssembly.compile(buffer))
.then(module => {
// 建立 WebAssembly 实例
return new WebAssembly.Instance(module, {env: env})
})
}
loadWebAssembly('./dist/module.optimized.wasm')
.then(instance => {
const {
sqart
} = instance.exports
console.log("5 sqart is: ", sqart(5));
})
复制代码
在index.html里调用封装好的wasm模块,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>webassembly</title>
</head>
<body>
<div id="box">
webassembly test
</div>
</body>
<script src="./index.js"></script>
</html>
复制代码
在浏览器中打开index.html,能够看到控制台里已经打印出结果:
已经知道Webassembly在nodeJs和浏览器中如何使用,那是否是能够知足我对性能提高的要求呢,我须要作一下速度对比测试。计算斐波拉切数列是一个不错的测速方式,在src/index.ts添加计算斐波拉切数列的方法,index.ts代码以下:
export function sqart (a: number): number {
return a * a;
}
export function fibonacci (n: number): number {
if ( n <= 2 ) {
return 1;
}
return fibonacci(n - 2) + fibonacci(n - 1);
}
复制代码
在根目录执行npm run build从新生成wasm代码。 看一下在nodeJs中的速度对比,这须要对nodejs/index.js的代码作一下改造,改造后的代码以下:
var myModule = require("./module.js");
function fibonacciJS(n) {
if ( n <= 2 ) {
return 1;
}
return fibonacciJS(n - 2) + fibonacciJS(n - 1);
}
const startTime = Date.now();
myModule.fibonacci(50);
console.log("wasm fibonacci(45) time is: ", `${Date.now() - startTime}ms` );
const jstartTime = Date.now();
fibonacciJS(50);
console.log("js fibonacci(45) time is: ", `${Date.now() - jstartTime}ms` );
复制代码
运行结果以下:
有声音说Webassembly能够取代javascript,可是我的认为短期内javascript是不可替代的,Webassembly只是javascript的一个补充和完善,它将更多的编程语言带到了web中。 最近也准备把咱们java大神写的UA识别神器(对市面所有的UA识别准确率达到90%以上)转换成wasm模块,而后前端直接调用,之后就不须要为了识别一个UA向服务端端发一次请求,没有Webassembly以前,这是不敢想的。 Webassembly已是一个标准并被四大浏览器厂商积极支持,虽然它如今还有一些不完美的地方,好比加载须要写胶水代码。可是随着时间的推移,它会愈来愈完善,web的性能会愈来愈高,将来咱们可能会进入一个告别安装应用的时代,全部的应用都变成web应用,即开即用,但愿这一天早日到来吧。