usb c ケーブル【1m+1m+2m+2m 4本】タイプc ケーブル Type C 3A急速充電 QC3.0対応 急速充電 PD対応 ナイロン編み 断線防止iPhone 16/15 Samsung/Note/Huawei Sony Xperia Nintendo Switch/GoPro その他Android USB-C機器対応
¥799 (2025年4月25日 13:07 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)【2025最新型】icカードリーダー マイナンバーカード対応 USB-A&Type-C 接触型 sdカードリーダー 設置不要 自宅で確定申告 国税電子申告 納税システム e-Tax対応マイナンバーカード ICチップ付いた住民基本台帳カード SDカード/マイナンバーカード/キャッシュカード その他対応 Windows11/10/8/7/Vista/macOS 10.16以降 日本語説明書付き
¥1,299 (2025年4月25日 13:05 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)USB C ケーブル タイプc 1M/2M 各2本 PD対応 60W超急速充電 断線防止 高速データ転送 Type-C to Type-Cケーブル for iPhone 16/15 Pro/Plus/Pro Max MacBook iPad Galaxy Sony Google Pixel 7a等USB-C各種対応
¥699 (2025年4月25日 13:05 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)
WebAssembly 興味あるけど何?調べても、どうやって動いてるのかさっぱりわからないんだけど…という方多いのではないでしょうか!自分もそうでした 😂
この記事では、 WebAssembly の目指しているゴールをその具体例とともに示し、みなさんの今後の深堀りを行うためのインデックスとしてお役にたてれば幸いです!なお、この記事は以下のような読者を想定しています。
- WebAssembly がどういうものか知りたい人
- 自分が作った WebAssembly がブラウザで実行されるまでの仕組みを知りたい人
以下に書いてあることのほとんどは MDN に書いてあることをベースに、自分なりに丁寧に書き下したものになります。
非常によくまとまっているので、この記事と併せて読んでいただけると、より理解が深まると思います 💪
この技術が登場したことの背景を理解することは WebAssembly を理解するもっとも近い道筋です。ここでは必要最低限の背景の説明に留めております。
ブラウザに足りなかったもの
ブラウザは HTML、CSS、JavaScript を解釈してそれをユーザーに見せるためのプログラムです。サイト配信者はその 3 つの言語を組み合わせ、ユーザーに配信することでさまざまなコンテンツを届けてきました。
多くのユースケースではこの 3 種類の言語の組み合わせで十分でしたが、ゲームや機械学習ではどうでしょうか?物理演算や機械学習モデルの計算など、メモリを大量かつ高速に扱うケースは JavaScript にとって荷が重いタスクです。一般的にインタプリタ言語がコンパイル言語と比べてその性能が低いことはソフトウェアエンジニアにはよく知られていることでしょう。
より詳細な歴史的経緯やその変遷は他の文献に委ねますが、端的に言えば WebAssembly 登場以前ではブラウザでネイティブに近い実行速度でプログラムを実行させるための仕組みが必要とされていたことが背景にあります。
WebAssembly の誕生
そういった経緯で誕生した規格が WebAssembly です。WebAssembly の前身に相当するものが C/C++ をソースとしてコンパイルしたものを利用していた経緯もあり、この規格は C/C++ や Rust といったメモリ効率の高い言語をコンパイルすることを念頭に設計されています。
WebAssembly は Web 標準として組み込まれるために以下の 4 つの要項を挙げています。
- 高速かつ高効率、そしてポータブルであること
- 可読性があり、デバッグ可能であること
- 安全であること
- ウェブを破壊しないこと
それぞれについて、詳しく見ていきましょう 👀
1. 高速かつ高効率、そしてポータブルであること
誕生背景の直接的な理由はおおよそこれであることが考えられます。では、これを達成するためにはどうすればよいのでしょうか?鍵となるのはバイトコードと仮想スタックマシンです。
バイトコード
バイトコード(英: bytecode / byte code)は、バイト指向の、中間表現のコードすなわち中間コードの総称である。
バイトコードは私たちが直接書くものではありませんが、理解しておくべき大事な要素です。CPU はメモリを逐次与えられた命令に基づいて書き換えていきますが、その命令は多岐に渡ります。Apple M1 の登場初期、多くのプログラムが正しく動作しなかったのは Intel と Apple M シリーズ CPU の持つ命令セットが異なっていたため、Intel CPU 用の命令を持つソフトウェアが Apple M シリーズの CPU にその命令を送っても解釈されなかったことが原因です。
C++ で書いたプログラムをコンパイルするときに、それぞれの CPU に対して異なるバイナリを生成しなければならないのはそういった背景があります。各 CPU に対してコンパイルしたバイナリの処理速度は高速かつ効率的です。しかし、ウェブアプリのように実行環境が多岐にわたる場合、各環境に対応したバイナリを個別に生成するのはあまり現実的でありません。
その課題を解決するのがバイトコードです。バイトコードは CPU のアーキテクチャに依存しない抽象度を保ちつつ、低レベルの命令(機械語)への変換を効率的に行うことができるように設計された中間表現になります。 JVM、.NET や JIT コンパイルされた Python はバイトコードを利用しています。これによりアプリケーションやライブラリ制作者は、ランタイムが環境差異を吸収してくれることから、一度バイトコードを生成すれば、どの環境でも実行できるようになります。
仮想スタックマシン
上のバイトコードを実行するための概念として仮想スタックマシンが登場します。まずは以下の例を見てください。
義務教育で習ってきたよくみる数値計算の記法は演算子を間に配置するものです。
1 + 2 * 3 = 1 + 6 = 7
これを、逆ポーランド記法 を用いて表現すると以下の表現になります。
1 2 3 * +
= 1 6 + # `*` 演算子はスタックに積み上げられていた 2 と 3 を取り出して 6 を戻している
= 7
ここでは、左から順番に数値を積み上げていき、演算子が出現したらその数値を取り出して計算しています。
スタックマシンはこのように、スタックに値を積み上げることと取り出して演算子を適用することを繰り返すことで計算します。
WebAssembly ではこのスタックマシンがバイトコードを実行するための、型、命令セット、メモリモデルを定義しています。そして、この仕様を実装し実際に動作させるためのソフトウェアのことを Embedder と呼んでいます。
2. 可読性があり、デバッグ可能であること
バイトコードは人間が理解するには難しく、コードがどのように実行されているのか理解しづらいです。そのような状況はネイティブアプリならともかく、ブラウザで動作するプログラムとしては好ましくないです。JavaScript と同様に開発者ツールでブレークポイントを貼って動作が理解できるとよさそうです。
バイナリ形式とテキスト形式
それを実現するための仕様として、WebAssembly には バイナリ形式 (WebAssembly Binary Format) と テキスト形式 (WebAssembly Text Format) の 2 つの表現方式が定義されています。バイナリ形式は、#バイトコード の WebAssembly における表現方式になります。特徴的なのはテキスト形式でこれは バイナリ形式と等価でありつつも人間が読めるような表現であること です。
たとえば、渡された 2 つの引数を足し合わせた数を返す add
関数を作ってみましょう。
add.wat
(module
;; 関数を定義する
(func $add (param i32 i32) (result i32)
;; ^関数名 ^引数 ^戻り値
local.get 0
local.get 1
i32.add
;; スタックに積みあげられた2つの引数を取り出して足し合わせている
return
)
;; 関数を公開する
(export "add" (func $add))
)
バイナリ形式 (wasm) とテキスト形式 (wat) はオンラインで手軽に変換するための デモサイト が用意されています。あるいはローカルで試したい場合には wasm-tools を使うとよいでしょう。
shell
$ wasm-tools parse add.wat -o add.wasm
$ ls -l
total 16
-rw-r--r--@ 1 shusann staff 48 Apr 5 17:03 add.wasm
-rw-r--r-- 1 shusann staff 257 Apr 5 17:02 add.wat
生成された add.wasm
はバイナリ形式 (wasm) でテキスト形式 (wat) よりファイルサイズが小さくなっていることがわかります。そして、おもしろいのはここからテキスト形式に戻せることです
shell
$ wasm-tools print add.wasm
(module
(type (;0;) (func (param i32 i32) (result i32)))
(export "add" (func $add))
(func $add (;0;) (type 0) (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
return
)
)
つまり、ウェブアプリケーション文脈において配信者は軽量なバイナリ形式にコンパイルしたファイルを配布し、必要に応じてブラウザでそれをテキスト形式に戻すことで可読性とデバッガビリティを担保しているというわけです。配信された wasm ファイルは実際に開発者ツールでデバッグできます。
デバッグ
たとえば、 Google Earth は 3D のレンダリングを WebAssembly で行っています。ネットワークタブを実際に見ると、ダウンロードされていることが確認できます。
wasm ファイルを開くとテキスト形式に変換されます。さらに、ブレークポイントを貼るとその時点におけるローカル変数やコールスタックなどを確認できます。
3. 安全であること
多くのプログラムの脆弱性はメモリへの不正なアクセスが理由となっていることが多いことは有名な話だと思います。WebAssembly Embedder の仕様として各インスタンスが与えられたメモリ以外へのアクセスを認めず、与えたメモリ領域を超えたアクセスが試みられた場合プログラム自体を終了 (trap) することを仕様としていることで安全性を担保しています。
4. ウェブを破壊しないこと
WebAssembly は既存のエコシステムを置換するものではなく、今まで足りなかった部分を補うものとして作られました。これは Google Earth の例 でも確認できるようにウェブアプリケーションを構成するコンポーネントの 1 つとして組み込まれ、JavaScript と相互に利用できるように設計されています。
ブラウザは WebAssembly が想定する Embedder としては第 1 村人です。その仕様は WebAssembly JavaScript Interface で定義されています。WebAssembly と JavaScript を相互に呼び出すことは、 import
と export
の 2 つコンポーネントを使って実現します。以下の例では、 demo.wat
が Embedder であるブラウザから import1
と import2
を受け取り、それらを呼び出しています。また、ブラウザからは WebAssembly から export された f
関数を呼び出しています。
demo.wat
(module
;; 後述の import Object で注入される関数をここで import する
(import "js" "import1" (func $i1))
(import "js" "import2" (func $i2))
;; main 関数は import1 関数を呼び出す
(func $main (call $i1))
(start $main)
;; import2 関数を呼び出すものを f として export する
(func (export "f") (call $i2))
)
browser の js
var importObj = {js: {
import1: () => console.log("hello,"),
import2: () => console.log("world!")
}};
fetch('demo.wasm').then(response =>
response.arrayBuffer()
).then(buffer =>
WebAssembly.instantiate(buffer, importObj)
).then(({module, instance}) =>
instance.exports.f()
);
このようにして、 WebAssembly は既存のウェブを破壊することなく、うまく統合されるようにデザインされています。
インターフェイスに違和感を覚えた?
一方、wasm のファイルを fetch
してインスタンス化する処理を書くのは手続き的で面倒に感じられます。WebAssembly はコアコンセプトに ES Module を意識した モジュール を定義していて、理想的には import
を使ってモジュールをインポートできるとよさそうです。
ES Module としてモジュールをインポートするための仕様は目下標準化に向けて進行中で ES Module Integration Proposal for WebAssembly でトラッキングされています。JS Embedding Interface を実装している deno はこれにいちはやく対応していて、ブラウザでも将来的に以下のようによりエルゴノミックに WebAssembly を利用できるようになるでしょう。
Deno 2.1
import { add } from "./add.wasm";
console.log(add(1, 2));
さて、ここまでで WebAssembly がどういうもので何ができるのかわかったと思います。それを踏まえて、今回は Go で WebAssembly バイナリを作ってブラウザで動かしてみましょう。Go 1.24 では WebAssembly 用の go:wasmexport
ディレクティブが追加されました。
せっかくなのでそのディレクティブを使用して、 #バイナリ形式とテキスト形式 のセクションで作成した add
関数と同じものを Go で実装してみます。以下に紹介するコードはデモレポジトリ (shusann01116/go-wasm) で公開しているので併せて参照してください。
まずは、テキスト形式をおさらいします。
add.wat
(module
;; 関数を定義する
(func $add (param i32 i32) (result i32)
;; ^関数名 ^引数 ^戻り値
local.get 0
local.get 1
i32.add
;; スタックに積みあげられた2つの引数を取り出して足し合わせている
return
)
;; 関数を公開する
(export "add" (func $add))
)
32 ビット整数 2 つを受け取り、1 つを返す add 関数を定義しています。また、 export
コンポーネントを使って関数を公開しています。これを Go で表現すると以下のようになります。
add.go
package main
func main() {}
func add(a, b int32) int32 {
return a + b
}
Go のコードを WebAssembly にコンパイルするには GOOS=js
と GOARCH=wasm
を指定し、 go build
を実行します。
shell
$ GOOS=js GOARCH=wasm go build -o add.wasm
Go は WebAssembly の実行に専用のグルーコードを js で提供しており、それをあらかじめ読み込んでおく必要があります。
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
JS 内では、 wasm_exec.js
を読み込んでから、 add.wasm
をダウンロードしてインスタンス化します。
インスタンス化されたインスタンスは exports を通じてアクセスできます。
今回の例でいうと、 add
関数を result.instance.exports.add
として呼び出すことができます。
そして、ブラウザ上で実際に数字を入れてボタンを押下すると WebAssembly で計算された数値結果が表示されていることが確認できます 🎉
add.wasm
のファイルサイズ
Go は GC を採用しているため、そのランタイムも WebAssembly にコンパイルする必要があり、ファイルサイズが大きくなってしまいます。これはロード時間がユーザー体験に与える影響度の大きいウェブにおいて理想的ではない状態で、バイナリサイズを小さくするための工夫が必要です。そのため、組み込み系で動作する TinyGo や GC を採用していない Rust や C など言語が比較的有利であり、この文脈でそれら言語がよく登場する理由のうちの 1 つです。
たとえば Go でコンパイルした add.wasm
のファイルサイズは 1.5 MB ですが、これを TinyGo でコンパイルした場合は 100 KB 程度に縮小できます。
shell
$ tinygo build -o add-tiny.wasm -target wasm add.go
$ ls -lh add*.wasm
-rw-r--r--@ 1 shusann staff 106K Apr 5 20:22 add-tiny.wasm
-rwxr-xr-x@ 1 shusann staff 1.5M Apr 5 19:19 add.wasm
今回は WebAssembly が目指しているゴールがどのような形で実装されているかをなぞり、その上で実際に Go から WebAssembly バイナリを生成してブラウザで動作する一連の流れを追ってきました。当初のゴールであった WebAssembly の概要の理解が叶ったならば幸いですし、さらなる深堀りのための足がかりになれば嬉しいです 😊
本記事では WebAssembly をもっとアツくしているブラウザ外の Embedding API である WebAssembly System Interface (WASI) について触れることができませんでした。本当はこれについても触れたかったのですが、記事が長くなりすぎるので別の機会に触れることとします 😢
まだまだ発展途上な WebAssembly ですが、すでに多くのエコシステムに影響を与えていてこれからの発展が非常に楽しみです!
それではよき WebAssembly ライフを! 🏖