2019/01/09
ネイティブアプリ並みのパフォーマンス!WebAssemblyでフロントエンド開発が変わる
JavaScriptは現在のWeb上で欠かせないものとなっています。近年のWebアプリケーションは物理演算や画像・音声・映像の処理、人工知能といったネイティブアプリと同じような機能や動作が求められるようになってきています。また、ユーザー側の端末のパフォーマンスが大幅に向上してきたことから、以前はサーバー側で行っていた処理をフロントで行うようになってきているため、フロントのプログラムはより複雑に、大規模なものが必要になってきています。
しかし、そのような複雑で大規模な処理をJavaScriptだけで行うことに限界が出てきていました。JavaScriptは元々複雑な処理や大規模な開発を前提としたプログラム言語ではないため、言語の特性上、複雑な処理や大規模なプログラムでは動作が遅くなってしまう弱点を抱えています。3Dの処理など、一部の機能はWebGLをはじめとしたJavaScriptの標準APIが追加されるなどして対応されてきましたが、更に新たな機能が必要になった場合は新たなAPIの開発と浸透を待たなければなりませんでした。
その問題に対応するために登場したのがWebAssemblyです。WebAssemblyはアセンブリ言語に似たWeb上で動作するプログラム言語で、ネイティブ並みの高速な処理が可能です。また、CやC++といったメモリ管理が可能で大規模なプログラムが得意な言語からのコンパイルが可能なため、JavaScript言語だけではできなかったような開発が可能になります。
そこで今回は、WebAssemblyについて調べてまとめてみました。
プログラムが実行されるとき、最終的には機械語という人間には読むことが困難なコードのかたちで実行されます。
1 | 10110000 01100001 |
この機械語をほぼそのまま人間に読める言語に置き換えたプログラム言語がアセンブリです。
1 | MOV AL, 61h |
JavaScript、PHP、Cなどはさらに人間にとって読みやすい言語になっていて、高級言語に分類され、アセンブリは低水準言語に分類されます。
1 | var n = 97 |
アセンブリのメリットは、機械語に近いので、翻訳に時間がかからず、高速であることです。デメリットは人にとって難解であることです。
ii. WebAssemblyとは?
WebAssemblyは、JavaScriptの苦手な高速な処理を担うために開発が進められているもので、アセンブリと同じく機械語に近い低水準言語に分類されます。アセンブリと文法などは違っており、ブラウザー上ではバイナリの形式で読み込まれます。
1 2 3 | 20 00 42 00 51 |
バイナリの形式のままだと難読なため、中間のテキストフォーマットが定義されています。
1 2 3 | get_local 0 i64.const 0 i64.eq |
とはいえ、これでも人間にとって難解なコードであることには代わりありません。
しかしながら、WebAssemblyはC/C++やRustなどの高級言語からのコンパイルを前提としているため、WebAssemblyのコードを直接記述する機会はほとんどありませんのでご安心ください。
また、WebAssemblyはJavaScriptの代替となる言語ではなく、JavaScriptを補完する目的で開発されたもので、WebAssemblyで実装したモジュールをJavaScriptで呼び出すという使い方を行います。
iii. WebAssemblyが使えると、何がいいのか?
WebAssemblyが使えると、JavaScript標準のAPIにない、例えば物理演算のようなパフォーマンスを必要とするプログラムをWebAssemblyで実装することで、処理を劇的に高速化することが可能になります。また、C/C++などで公開された既存のソースをWebAssemblyにコンパイルして利用することも可能になるため、Web上でできることが大きく広がります。
また、メモリ管理ができると心配になるのがセキュリティですが、WebAssemblyはネイティブな環境からは隔離されたブラウザの仮想環境で実行されるため、セキュリティ面も安心して開発できます。
2. 使ってみよう(C/C++で開発する場合)
i. Emscriptenのインストール
WebAssemblyは基本的にC、C++、Rust、Goといった高級言語で開発したものをコンパイルして利用します。今回はC、C++で開発する場合の方法をご紹介いたします。
まず、Emscriptenをインストールします。
インストール方法は「C/C++からWebAssemblyにコンパイルする | MDN」←こちらがわかりやすいです。
ii. コードの確認とコンパイル
今回はテキストを表示するだけの簡単なサンプルプログラムをコンパイルしてみます。
hello.c というファイルを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> #include <emscripten/emscripten.h> int main(int argc, char ** argv) { printf("Hello World\n"); } #ifdef __cplusplus extern "C" { #endif void EMSCRIPTEN_KEEPALIVE testMyFunction(int argc, char ** argv) { printf("testMyFunction called\n"); } #ifdef __cplusplus } #endif |
以下のターミナルでhello.cを作成したディレクトリに移動し、以下のコマンドを実行し、コンパイルします。
1 | emcc hello.c -s WASM=1 -o hello.html -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" |
hello.wasm, hello.js, hello.htmlが出力されます。
もしEmscriptenが無事にインストールされた後に「command not found: emcc」と出るようでしたら、
以下のコマンドを実行してからもう一度上記のコマンドを実行してみてください。(私はここで引っかかりました)
1 | source /[Emscriptenをダウンロードしたディレクトリ]/emsdk/emsdk_env.sh |
hello.htmlから必要なコードを取り出し、実装するHTMLに配置します。
iii. ブラウザで実行
↑今回作ってみたものです。現状、IEを除く最新のモダンブラウザで実行できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <p id="output"></p> <button class="mybutton">Run testMyFunction</button> <script> var Module = { preRun: [], postRun: [], print: (function() { var element = document.getElementById('output'); if (element) element.value = ''; // clear browser cache return function(text) { if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); console.log(text); if (element) { element.innerText += text + "\n"; element.scrollTop = element.scrollHeight; // focus on bottom } }; })(), printErr: function(text) { if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); console.error(text); } }; window.onerror = function(event) {}; document.querySelector('.mybutton').addEventListener('click', function(){ var result = Module.ccall('testMyFunction', // name of C function null, // return type null, // argument types null); // arguments }); </script> <script async type="text/javascript" src="hello.js"></script> |
もちろん今回のようなテキストを表示するだけのコードでしたら、JavaScriptだけで記述したほうが高速で軽量ですが、規模が大きかったり複雑だったりする処理が必要な場合は、今後欠かせないものになりそうです。
参考にさせていただいたサイト
WebAssembly: 「なぜ」と「どうやって」 [翻訳記事] – DEV Community 👩💻👨💻
Author Profile
NINOMIYA
Webデザイナー兼コーダー出身のフロントエンド開発者です。 UXデザインやチーム開発の効率化など、勉強中です。
SHARE