メインコンテンツへスキップ
ブログ一覧に戻る
Web制作・運用

WebAssembly入門:JavaScriptとの役割分担と、小さく試す判断基準

2024年7月23日
最終更新: 2026年10月8日
9分で読めます

この記事でわかること

WebAssemblyはJavaScriptと組み合わせて処理を実行する選択肢です。小さな加算モジュールを動かし、ホストとの境界、性能測定、メモリの安全性、WASIの条件を整理します。

2026年10月8日にWebAssembly 3.0の実行意味論とMDN WebAssembly本文を再確認した。WebAssemblyはブラウザーや他のホストで実行できる低レベルのポータブルな形式で、線形メモリ、モジュール、インポート/エクスポート、ホストとの境界を持つ。高速化が必要な計算に使えても、ネットワーク・DOM・ファイル・秘密への権限はホストが与える範囲に限られ、性能、サイズ、デバッグ、サンドボックス、供給元を測定して採用する。

30秒で要点

WebAssembly(Wasm)は、実行環境が読み込めるバイナリ形式と、その実行の仕組みです。C、C++、Rustなどから生成された処理を、ブラウザや対応ランタイムで使うための選択肢になります。

  • JavaScriptと役割を分け、必要な処理をモジュールとして呼び出せます。
  • 高速化は保証されません。読み込み、初期化、データの受け渡しまで測ります。
  • 実行の分離があっても、入力検証、権限、依存コード、メモリの扱いは確認が必要です。

最初から画面全体を置き換えるより、重い処理や再利用したいライブラリを一つ選び、導入費用に見合うかを確かめます。

WasmとJavaScriptは、どこでつながるのか

Wasmは、そのままCPUへ渡す特定機種用の機械語ではありません。対応する実行環境が形式を検証し、コンパイルなどを経て実行します。人が読めるテキスト表現をWATと呼びます。

ブラウザでは、JavaScriptがモジュールを読み込み、公開された関数を呼び出せます。Wasm側から使いたい関数や値を、ホスト側が渡すこともできます。MDNの主要概念では、次の区別が説明されています。

表が収まらない場合は、横にスクロールできます

用語役割
Moduleコンパイルされたコード。取り込む機能と公開する機能を定義する
InstanceModuleを実行に必要な状態と組み合わせたもの
importsホストなど外側から渡す関数や値
exports外側から利用できる関数や値
Memory低水準の読み書きに使う、バイト列としての線形メモリ

すべてのモジュールにメモリが必要なわけではありません。後の小さな加算例は、整数の引数と戻り値だけを使います。

JavaScriptが入力を検証し、引数をWasmの公開関数へ渡す。Wasmの結果をJavaScriptが受け取り画面へ反映する。ファイルや通信などの外部機能はホスト側の入口と権限を通る関係
図1:ブラウザでの代表的な役割分担。計算の実行と画面・外部機能の操作を分ける。どの機能を渡すか、どの結果を受け入れるかもアプリの設計に含む。

DOMの操作やWeb APIとの連携は、JavaScriptなどホスト側の入口を介して行います。WasmだけでHTMLの意味やキーボード操作、アクセシビリティが整うわけではありません。WebAssemblyのFAQも、JavaScriptを補完して併用する考え方を説明しています。

外部ファイルなしで、最小のモジュールを動かす

次のWATは、2個の32ビット整数を受け取り、足した結果を返すモジュールのテキスト表現です。addという名前で関数を公開しています。

(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))

通常は言語のツールチェーンやWATの変換ツールから.wasmを作ります。ここでは追加ツールを入れずに試せるよう、この加算モジュールに対応する41バイトをJavaScriptへ直接記述します。既存サイトから取得するファイルは必要ありません。バイト列の暗記や、実務での手書きを勧める例ではありません。

wasm-demo.mjsとして保存し、Node.js 24系でnode wasm-demo.mjsを実行します。サーバーも通信も使いません。

const bytes = new Uint8Array([
  0, 97, 115, 109, 1, 0, 0, 0,
  1, 7, 1, 96, 2, 127, 127, 1, 127,
  3, 2, 1, 0,
  7, 7, 1, 3, 97, 100, 100, 0, 0,
  10, 9, 1, 7, 0, 32, 0, 32, 1, 106, 11,
]);

if (!WebAssembly.validate(bytes)) throw new Error('Invalid Wasm module');
const { instance } = await WebAssembly.instantiate(bytes);
const add = instance.exports.add;
console.log(add(5, 10));
console.log(add(2147483647, 1));

出力は15と-2147483648になります。後者はエラーではなく、i32.addが32ビットの範囲で折り返す演算だからです。WebAssembly仕様の整数加算は、2の32乗を法とした計算を定めています。JavaScriptへ返ると符号付き32ビット整数として見えます。

この違いを知らずに、金額や件数を無制限に渡してはいけません。引数の範囲、丸め、文字列や配列の表現、エラー時の戻り方を境界の契約として決めます。instantiateの入出力と例外も確認してください。

本稿ではローカルNode.jsで、正常な加算、整数の折り返し、壊したバイト列の拒否を確認しています。この例はWasmを呼び出す流れを学ぶためのもので、JavaScriptより速いことを示すベンチマークではありません。WATからコンパイラで生成する工程やブラウザでの実行は、今回の検証範囲に含めていません。

速さを判断するなら、計算の前後も測る

Wasmの候補になるのは、画像・音声処理、圧縮、シミュレーションなどのまとまった計算や、既存のネイティブ向けライブラリの再利用です。ただし、元のコードが使うOS機能や依存関係も移植できるかを確認します。

小さな足し算を何度も境界越しに呼び出せば、受け渡しの費用が相対的に大きくなります。大きな配列をまとめて渡す場合も、コピー、文字列の符号化、メモリ確保の費用を無視できません。言語を替える前に、処理の組み方を見直す余地もあります。

表が収まらない場合は、横にスクロールできます

測定する区間見落としやすい条件
ダウンロード圧縮後の量、キャッシュの有無、追加ランタイム
コンパイルと初期化初回と再利用時、端末性能
入力の準備配列コピー、文字列変換、メモリ確保
実際の計算入力の大きさ、アルゴリズム、出力の同等性
結果の反映戻り値変換、画面更新、メインスレッドの占有

Wasmを使っても、重い同期処理をメインスレッドで呼べば、画面操作を待たせる場合があります。Workerへ移す案なら、通信・データ移動の時間も測定対象です。

比較時は同じ入力と同じ出力条件を使い、端末、実行環境、ビルド設定、初回か再利用かを記録します。中央値だけでなく、遅い側の値や失敗件数、最大メモリも見ます。たとえば「画像1枚の変換」なら、利用者がファイルを選んでから結果を使えるまでを測ると、計算だけが速くなった錯覚を避けられます。

sandboxは、アプリの安全性全体を保証しない

Wasmの実行はホストから分離され、モジュールが外の機能を使うには適切な入口が必要です。ただし、これはアプリの入力や業務上の権限が正しいことを意味しません。

CやC++由来のコードでは、線形メモリの範囲内で隣のデータを書き換える問題が残り得ます。メモリ領域の外へ出られないことと、領域内の各オブジェクトが壊れないことは別です。WebAssemblyのセキュリティモデルとMemory Safety

ホストから渡す関数にも注意します。ファイルの全読み書きや任意URLへの通信を許す関数を渡せば、その権限の範囲で作用できます。依存モジュールの出所と更新、入力サイズ、許可する外部操作、処理の時間とメモリを確認します。機密情報をブラウザへ渡した後に、Wasmだから読めなくなるとは考えないでください。

バイナリの検証に成功しても、業務ロジックの誤りや無限に近い計算がなくなるわけではありません。信頼できない処理を動かす用途では、実行環境が提供する制限や停止手段まで検討します。

配信とWASIは、別の確認項目を持つ

ブラウザでは、配信条件と機能対応を確認する

本番の配信では、生成した.wasmファイルを配置し、読み込み失敗も扱います。WebAssembly.instantiateStreaming()を使う場合、サーバーはapplication/wasmのMIME型を返す必要があります。ストリーミング読み込みの条件

サイトのCSP、必要な機能への対応、キャッシュ更新も確認対象です。「Wasm対応ブラウザ」という一つの判定だけでは、使う拡張機能まで動くとは言えません。未対応時に処理を止めて説明するのか、JavaScript版へ切り替えるのかを決めます。古いJSと新しいWasmの組合せが配信されないよう、成果物の対応も管理します。

WASIは、ホストの機能を使うためのAPI仕様群

WASI(WebAssembly System Interface)は、Wasmがファイルや通信などのホスト機能を利用するためのAPI仕様群です。単独のサーバー製品や、ブラウザのDOM操作APIの名前ではありません。WASIの公式紹介

実行するモジュールやコンポーネントが要求するインターフェースと版、ランタイムの実装状況を合わせます。さらに、どのディレクトリや通信先へアクセスできるかをホスト側で決めます。同じWasmファイルなら、どのWASI環境でも無条件に同じ動作をするわけではありません。

ブラウザ向け処理、サーバー内のプラグイン、WASIコンポーネントでは、配布形式と入口が異なる場合があります。最初に実行先を決めてから、言語とツールチェーンを選びます。

最初は、入力と結果を比較できる処理を一つ選ぶ

導入前に、今の遅さが計算、通信、描画のどこにあるかを測ります。通信待ちが主因なら、計算部分をWasmへ移しても大きく改善しないかもしれません。

候補を一つ決めたら、正常入力に加えて、空入力、大きな入力、不正な入力を用意します。既存実装と結果を照合し、初回の待ち時間、繰り返し時の時間、メモリ、配信量を比較します。Wasm版の読み込みが失敗したときの表示も確認します。

改善が小さいなら、配信と更新を複雑にする費用を上回るか再考します。速くなる処理が見つかっても、対応端末の範囲や保守できる言語・ツールを含めて採用を決めます。今回確認した最小例の成功だけで、サイトの高速化や安全性を判断しないことが大切です。

計測から改善箇所を選ぶ手順はWebパフォーマンス入門、型と実データの境界はTypeScriptとZodによる入力検証、配信後の更新・復旧は運用保守ガイドで補えます。

よくある質問(FAQ)