最近在破解網站驗證碼的時候,圖像識別速度上遇到一點瓶頸。按照我如今的代碼,從獲取到驗證碼圖片到輸出正確驗證碼字符串須要等待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應用,即開即用,但願這一天早日到來吧。