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を組み合わせることで、WasmのスピードとNode.jsの多様性を兼ね備えた環境が得られます。
環境の設定
コードに取り組む前に、まずは作業環境を整えましょう。心配しないでください、新しいスマートフォンを設定するよりも簡単です!
- 公式サイトからNode.jsをインストールします(https://nodejs.org)
- ターミナルまたはコマンドプロンプトを開きます
- プロジェクト用の新しいディレクトリを作成します:
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>
は、CをWebAssemblyにコンパイルするのに役立つEmscriptenライブラリをインクルードします。 -
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
おめでとうございます!あなたは初めてのWebAssemblyモジュールをNode.jsで実行しました!
性能比較
さて、私たちの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
関数を100万回実行し、それぞれの実行時間を計測します。
スクリプトを再実行すると、WebAssembly版がより早いと感じるでしょう!
結論
私たちはWebAssemblyとNode.jsの可能性の一部しか触れていません。考えてみてください、CやRustで書かれた複雑なアルゴリズムやゲームエンジン、甚至是非のアプリケーションが、ほぼネイティブスピードでNode.jsで動作するなど、どんな可能性があるか!
コードを学ぶことは、自転車に乗るのと似ています。最初は不安定かもしれませんが、練習を積むことですぐにスムーズに乗れるようになります。実験を続け、学び続け、そして何より楽しみましょう!
以下に、私たちが使用した主なメソッドをまとめた表を示します:
メソッド | 説明 |
---|---|
WebAssembly.instantiate() |
WebAssemblyモジュールをコンパイルおよびインスタンス化します |
fs.readFileSync() |
ファイルを同期的に読み込みます |
path.join() |
パスセグメントを結合します |
console.time() |
タイマーを開始します |
console.timeEnd() |
タイマーを終了し、経過時間をログします |
未来のWebAssemblyウィザードたち、快適なコーディングを!
Credits: Image by storyset