WebAssembly - 在 Node.js 中使用
你好,有志者!今天,我們將踏上一段令人興奮的旅程,進入 WebAssembly 和 Node.js 的世界。別擔心,如果這些術語對你來說像外星語言一樣陌生 - 在這個教程結束時,你將能夠流利地使用它們!
WebAssembly 是什麼?
WebAssembly,通常縮寫為 Wasm,在編程世界中就像一個超人。它是一種二進制指令格式,讓用 C、C++ 和 Rust 等語言編寫的代碼能在網頁瀏覽器中以接近本地速度運行。想像一下能夠在瀏覽器中直接玩複雜的 3D 遊戲 - 這就是 WebAssembly 帶給我們的力量!
為什麼是 Node.js?
現在,你可能會想,"Node.js 和這有什麼關係?" 這樣說吧,Node.js 就像幕後工作人員,讓魔術發生。它是一個 JavaScript 執行環境,讓我們能在網頁瀏覽器之外運行 JavaScript。當我們將 WebAssembly 和 Node.js 結合起來時,我們得到了兩者的最佳組合 - WebAssembly 的速度和 Node.js 的多用途性。
設置我們的開發環境
在我們深入代碼之前,讓我們先設置我們的工作空間。別擔心,這比設定新手機還要容易!
- 從官方網站(https://nodejs.org)安裝 Node.js
- 打開你的終端機或命令提示符
- 為我們的專案創建一個新目錄:
mkdir wasm-nodejs-tutorial cd wasm-nodejs-tutorial
- 初始化一個新的 Node.js 專案:
npm init -y
太好了!現在我们可以開始編寫代碼了。
你的第一個 WebAssembly 模塊
讓我們創建一個簡單的 WebAssembly 模塊來將兩個數字相加。我們將用 C 語言寫它,並將它編譯為 WebAssembly。
步驟 1:編寫 C 代碼
創建一個名為 add.c
的文件,並將以下內容添加到其中:
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
別擔心如果這看起來像象形文字!讓我們分解一下:
-
#include <emscripten.h>
引入 Emscripten 圖書,它幫助我們將 C 編譯為 WebAssembly。 -
EMSCRIPTEN_KEEPALIVE
是一個特殊指導,告訴編譯器保留這個函數,讓它能從 JavaScript 調用。 -
int add(int a, int b)
是我們的函數,它接受兩個整數並返回它們的和。
步驟 2:編譯為 WebAssembly
為了將這段 C 代碼編譯為 WebAssembly,我們需要安裝 Emscripten。遵循 Emscripten 網站上的安裝說明(https://emscripten.org/docs/getting_started/downloads.html)。
安裝完畢後,運行以下命令:
emcc add.c -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -o add.js
這個命令將我們的 C 代碼編譯為 WebAssembly,並創建兩個文件:add.wasm
和 add.js
。
在 Node.js 中使用 WebAssembly
現在到了令人興奮的部分 - 在 Node.js 中使用我們的 WebAssembly 模塊!
創建一個名為 index.js
的文件,並將以下內容添加到其中:
const fs = require('fs');
const path = require('path');
const wasmBuffer = fs.readFileSync(path.join(__dirname, 'add.wasm'));
WebAssembly.instantiate(wasmBuffer).then(wasmModule => {
const add = wasmModule.instance.exports._add;
console.log('5 + 3 =', add(5, 3));
});
讓我們分解一下:
- 我們導入必要的 Node.js 模塊:
fs
用於文件系統操作和path
用於文件路徑操作。 - 我們讀取 WebAssembly 文件到緩存區。
- 我們使用
WebAssembly.instantiate()
來加載和編譯我們的 WebAssembly 模塊。 - 加載完畢後,我們可以通過
wasmModule.instance.exports._add
調用我們的add
函數。 - 最後,我們調用我們的函數並記錄結果。
使用以下命令運行此腚本:
node index.js
如果一切正常,你應該會看到:5 + 3 = 8
恭喜你!你剛好在 Node.js 中運行了你的第一個 WebAssembly 模塊!
性能對比
現在,讓我們比較一下我們的 WebAssembly 函數和本地 JavaScript 函數的性能。
將以下內容添加到你的 index.js
:
function jsAdd(a, b) {
return a + b;
}
const iterations = 1000000;
console.time('WebAssembly');
for (let i = 0; i < iterations; i++) {
add(5, 3);
}
console.timeEnd('WebAssembly');
console.time('JavaScript');
for (let i = 0; i < iterations; i++) {
jsAdd(5, 3);
}
console.timeEnd('JavaScript');
這段代碼分別運行我們的 WebAssembly 和 JavaScript 版本的 add
函數一百萬次,並計算各自的運行時間。
再次運行腚本,你很可能會看到 WebAssembly 版本更快!
結論
我們只是輕輕地刮了一下 WebAssembly 和 Node.js 所能實現的表面。想像一下可能性 - 你可以使用 C 或 Rust 編寫的複雜算法、遊戲引擎,甚至是整個應用程序,所有這些都能在 Node.js 中以接近本地速度運行!
記住,學習編程就像學習騎自行車一樣。起初可能會有些晃動,但隨著練習,你會很快騎得飛快。持續試驗,持續學習,最重要的是,玩得開心!
這裡是一個總結我們使用的主要方法的表格:
方法 | 描述 |
---|---|
WebAssembly.instantiate() |
編譯和實例化一個 WebAssembly 模塊 |
fs.readFileSync() |
同步讀取一個文件 |
path.join() |
連接路徑段 |
console.time() |
開始一個計時器 |
console.timeEnd() |
結束一個計時器並記錄時間 |
祝編程愉快,未來的 WebAssembly 巫師們!
Credits: Image by storyset