今回紹介するのは、WebAssemblyです。これは、その名の通りWebブラウザ上で動かせるアセンブリ風の言語です。既に、C/C++言語、RustやGo言語などのプログラミング言語がWebAssemblyに対応しています。また、主要Webブラウザではサポートされており、JavaScriptよりも高速に実行できるため、ブラウザの可能性が大きく広がっています。今回は、WebAssemblyについて、また、実際にブラウザで実行する方法を紹介します。

  • Go言語でWebAssemblyを出力して実行したところ

    Go言語でWebAssemblyを出力して実行したところ

ブラウザにはJavaScriptがあるのになぜ?

WebAssemblyはWebブラウザ上で動作する言語です。しかし、Webブラウザ上で動作する言語には、既にJavaScriptがあります。モダンブラウザであれば、どのブラウザを使っても同じようにJavaScriptのプログラムを動かすことができます。しかも、JavaScriptは大幅に改良され続けています。それでは、なぜ、WebAssemblyが必要となったのでしょうか。

結論を言えば、実行速度を高速にするためです。もちろん、JavaScriptは動的で柔軟性の高いプログラミング言語ですが、その長所の裏返しとして、C言語やJavaなどの静的型付け言語と比べると遅くなります。

今やWebブラウザはあらゆる場面で使われており、JavaScriptではパフォーマンスが出ないという場面が増えてきました。どんなものにも向き不向きがあるのは仕方ないことでしょう。JavaScriptは大量の計算を高速にこなすのには向いていないのです。そこで、WebAssemblyの登場です。

WebAssemblyとは何なのか?

ところで、WebAssemblyとは一体なのでしょうか。『ブラウザで動かせるアセンブリ風の言語』と言ってもよく分からない方も多いことでしょう。そもそも、アセンブリ言語とは、コンピューターの脳に当たるCPUに対して直接命令を与えることのできる言語です。

アセンブリ言語は、一般的なプログラミング言語と違って高度な命令を手軽に記述することはできませんが、CPUに直接命令を与えることができるので、高速なプログラムを記述できます。WebAssemblyも同じで、それ自体を利用して、高度な命令を手軽に記述することはできませんが、高速に動作します。

とは言え、現在、アセンブリ言語を人間が書くことは少なく、C/C++言語などの高水準なプログラミング言語を利用してコンパイルして、機械的に作成するのが一般的です。WebAssemblyも同じで、C/C++/Rustなどの高水準なプログラミング言語からコンパイルして使うことが前提となっています。そして、コンパイル結果は、数値の羅列であるバイナリデータとなっています。

ただし、アセンブリ言語がCPUごとに異なるものであるのに対して、WebAssemblyは、あらゆるブラウザ上で動作する点が異なります。

JavaScriptは廃れる?

巷では、フィボナッチ数の計算などのテストで、WebAssemblyを使うと、JavaScriptよりも最大3倍ほど速くなると言われています。WebAssemblyの実行エンジンは改良されていますので、処理速度は今後もっと速くなることでしょう。

とは言え、すべての処理がJavaScriptよりも速くなるわけではありません。状況によっては、ほとんど同じ速度だったという場合もあります。WebAssemblyは数値計算を得意としているので、JavaScriptで手が回らないところをWebAssemblyに任せるなど、今後は用途に合わせて選んで使うことになるでしょう。

それに、JavaScriptはHTML内にプログラムを書けば、すぐに動かすことができますが、WebAssemblyはプログラムを一度コンパイルする必要があります。しかも、JavaScriptからWebAssemblyを読み込む必要があり、開発も実行もJavaScriptよりも手間のかかるものとなっています。そのため、WebAssemblyはJavaScriptを置き換えるものではなく、JavaScriptを補うものと考えるのが妥当です。

どんな言語が対応しているの?

原稿執筆時点では、C/C++言語、Rust、Go言語、Kotlin、Luaなど、既に多くの言語がWebAssemblyの出力に対応しています。

また、WebAssemblyのバイナリファイルを出力するのではなく、WebAssembly上で動くというのであれば、PythonやRubyなどのスクリプト言語も動かすことができます。

どうやって使うのか?

上記で紹介した言語ですが、各言語ごとにWebAssemblyの出力方法が異なります。

C言語やLuaからWebAssemblyにするためには、Emscriptenというツールを利用することができます。

RustやGo言語であれば、最初からその出力オプションが用意されています。そこで、本連載でも既に実行環境の構築方法などを紹介したGo言語を使ってみましょう。

※ただし、Go言語のWebAssembly機能はまだ安定しておらず、本稿ではGo言語のバージョン1.12.7で試しています。もし、動かない場合、こちらからGo言語の過去バージョンを利用してみてください。

Go言語でWebAssemblyを出力し、Webブラウザの画面に「こんにちは世界」と表示させてみましょう。まずは、Go言語でプログラムを書きます。ほかのGo言語のプログラムと変わりませんが、JavaScriptのAPIを利用するため、syscall/jsパッケージを取り込んで利用します。

package main
import (
    "fmt"
    "syscall/js"
)
func main() {
    fmt.Println("Go起動したよ")
    // JavaScriptのAPIを経由して、ブラウザのdocumentを取得
    document := js.Global().Get("document")
    // h1要素を作成
    h1 := document.Call("createElement", "h1")
    h1.Set("innerHTML", "こんにちは世界")
    // Body要素を得てh1要素を追加
    body := document.Get("body")
    body.Call("appendChild", h1)
}

上記のプログラムを「hello.go」という名前で保存します。プログラムの内容はコメントの通りで、Go言語からJavaScriptのAPIを呼び出して、HTMLのDOM構造を操作してメッセージを表示するというものになっています。

それでは、これをGo言語でWebAssemblyのバイナリファイル形式WASM形式にコンパイルします。コマンドラインで以下のコマンドを実行しましょう(Windowsならコマンドプロンプト、macOSならターミナル.appを利用できるでしょう)。

# Windowsの場合
set GOOS=js
set GOARCH=wasm
go build -o test.wasm hello.go




# macOSの場合
GOOS=js GOARCH=wasm go build -o test.wasm hello.go

このプログラムをブラウザで利用するために、JavaScriptのライブラリ「wasm_exec.js」と呼び出しサンプルの「wasm_exec.html」が必要です。これは、Go言語をインストールしたフォルダのmisc/wasmフォルダに入っています。(Windowsなら、"c:¥go¥misc¥wasm")そこから、今回のフォルダにコピーして使ってください。)

なお、内容が安定せず各バージョン毎に異なるファイルとなっています。必ず、ご利用のバージョンのものをご利用ください。

ちなみに、macOSなら以下のコマンドでコピーできます。

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
cp "$(go env GOROOT)/misc/wasm/wasm_exec.html" .

それから、呼び出し例の「wasm_exec.html」をWebブラウザで開いていましょう。しかし、ブラウザ画面を開いても何も起きません。ブラウザの開発ツールを起動してみると分かるのですが、セキュリティのエラーが表示されることでしょう。

  • WebAssemblyはローカルで直接実行することはできない

    WebAssemblyはローカルで直接実行することはできない

そうなんです。セキュリティ制約のため、WebAssemblyはローカルファイルを直接読み込んで実行することはできません。

そこで、Go言語でWebサーバーを起動して暫定的に利用しましょう。以下のプログラムを「server.go」という名前で保存しましょう。6行ですが簡易的なWebサーバーになります。

package main
import "net/http"
func main() { // メイン処理
    http.ListenAndServe(":8888", http.FileServer(http.Dir(".")))
}

先ほど、環境変数をWebAssemblyの設定に変更してしまったので、一度、コマンドラインのウィンドウを閉じ、改めて新しいコマンドラインを起動しましょう。そして、以下のコマンドを実行してWebサーバーを起動します。

go run server.go

サーバーが起動したら、改めてWebブラウザで http://localhost:8888/wasm_exec.html にアクセスしましょう。そして、[Run]ボタンをクリックすると、WebAssemblyがサーバーから読み込まれて実行され、以下のように表示されます。

  • WebAssemblyがブラウザで動いたところ

    WebAssemblyがブラウザで動いたところ

まとめ

以上、今回は、WebAssemblyについて、また、Go言語を利用して簡単にWebAssemblyを作成する方法について紹介してみました。

手順で確認すると分かりますが、WebAssemblyを作成するには、コンパイル作業が必要になります。そのため、プログラムを書いてすぐ動くJavaScriptのような簡易さは感じられないことでしょう。しかし、処理速度が高速なので、JavaScriptと上手に役割分担することで、効率的なWebアプリが開発できます。

また、これまでJavaScript一辺倒だったブラウザ上のアプリ開発を、いろいろな言語を使って開発できるようになったので、開発の自由度が上がり、開発者にとっては嬉しい技術です。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2005年IPAスーパークリエイター認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。