blob: 9903ec8926f14c4899e3ed97c19085e98ad633b0 (
plain)
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
---
title: WebAssemblyコードのロードと実行
slug: WebAssembly/Loading_and_running
tags:
- Fetch
- JavaScript
- WebAssembly
- XMLHttpRequest
- バイトコード
translation_of: WebAssembly/Loading_and_running
---
<div>{{WebAssemblySidebar}}</div>
<p class="summary">JavaScript で WebAssembly を使用するには、まずコンパイル/インスタンス化の前にモジュールをメモリにプルする必要があります。この記事では、WebAssembly バイトコードをフェッチするために使用できるさまざまなメカニズムのリファレンスと、それをコンパイル/インスタンス化して実行する方法について説明します。</p>
<h2 id="What_are_the_options">どんな方法があるの?</h2>
<p>WebAssemblyは <code><script type='module'></code> または ES2015 の <code>import</code> 文とまだ統合されていないため、インポートを使用してブラウザでモジュールをフェッチする組み込みの方法はありません。</p>
<p>以前の {{jsxref("WebAssembly.compile")}}/{{jsxref("WebAssembly.instantiate")}} メソッドでは、生のバイトをフェッチした後 WebAssembly モジュールのバイナリを含む {{domxref("ArrayBuffer")}} を作成し、コンパイル/インスタンス化する必要があります。これは文字列(JavaScript ソースコード) をバイトの配列バッファ (WebAssembly ソースコード)で置き換えることを除いて、<code>new Function(string)</code> に似ています。</p>
<p>新しい {{jsxref("WebAssembly.compileStreaming")}}/{{jsxref("WebAssembly.instantiateStreaming")}} メソッドは、より効率的です。ネットワークからの生のバイトストリームに対して直接アクションを実行し、 {{domxref("ArrayBuffer")}} ステップの必要性がなくなりました。</p>
<p>では、どのようにバイト列を配列バッファに読み込んでコンパイルするのでしょうか? 次の章で説明します。</p>
<h2 id="Using_Fetch">Fetchを使用する</h2>
<p><a href="/ja/docs/Web/API/Fetch_API">Fetch</a> はネットワークリソースを取得するための便利でモダンな API です。</p>
<p>wasm モジュールをフェッチする最も簡単で効率的な方法は、新しい {{jsxref("WebAssembly.instantiateStreaming()")}} メソッドを使用することです。このメソッドは最初の引数として <code>fetch()</code> を呼び出すことができ、1つのステップでフェッチ、モジュールをインスタンス化し、サーバからストリームされる生のバイトコードにアクセスします。</p>
<pre class="brush: js">WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(results => {
// Do something with the results!
});</pre>
<p>直接ストリームでは動作しない古い {{jsxref("WebAssembly.instantiate()")}} メソッドを使用した場合、フェッチされたバイトコードを {{domxref("ArrayBuffer")}} に変換する必要があります。次のようにです:</p>
<pre class="brush: js">fetch('module.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
// コンパイルされた結果(results)で何かする!
});</pre>
<h3 id="Aside_on_instantiate_overloads">余談: instantiate() のオーバーロード</h3>
<p>{{jsxref("WebAssembly.instantiate()")}} 関数は2つのオーバーロードを持ちます — 1つ目 (上の例を参照)はバイトコードを受け取ってプロミスを返します。解決されたプロミスでコンパイルされたモジュールと、それをインスタンス化したものを含むオブジェクトとして受け取ります。オブジェクトの構造は以下のようになります:</p>
<pre class="brush: js">{
module : Module // コンパイルされた WebAssembly.Module オブジェクト,
instance : Instance // モジュールオブジェクトから生成された WebAssembly.Instance
}</pre>
<div class="note">
<p><strong>注</strong>: 通常はインスタンスのみを気にしますが、キャッシュする場合や、<code><a href="/ja/docs/Web/API/MessagePort/postMessage">postMessage()</a></code> を使用して別のワーカーやウィンドウと共有する場合や、インスタンスをさらに作成したい場合に備えて、モジュールを用意すると便利です。</p>
</div>
<div class="note">
<p><strong>注</strong>: 2番目のオーバーロードフォームは {{jsxref("WebAssembly.Module")}} オブジェクトを引数としてとり、結果としてインスタンスオブジェクトを直接含む Promise を返します。<a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate#Second_overload_example">2番目のオーバーロードの例</a>を参照してください。</p>
</div>
<h3 id="Running_your_WebAssembly_code">WebAssembly コードを実行する</h3>
<p>JavaScript 内で WebAssembly インスタンスが 有効になったら {{jsxref("WebAssembly.Instance/exports", "WebAssembly.Instance.exports")}} プロパティを通してエクスポートされた機能を使い始める事ができます。コードは以下のようになるでしょう:</p>
<pre class="brush: js">WebAssembly.instantiateStreaming(fetch('myModule.wasm'), importObject)
.then(obj => {
// Call an exported function:
obj.instance.exports.exported_func();
// or access the buffer contents of an exported memory:
var i32 = new Uint32Array(obj.instance.exports.memory.buffer);
// or access the elements of an exported table:
var table = obj.instance.exports.table;
console.log(table.get(0)());
})</pre>
<div class="note">
<p><strong>注</strong>: WebAssembly モジュールからのエクスポートの仕組みの詳細については <a href="/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript APIを使用する</a> と <a href="/ja/docs/WebAssembly/Understanding_the_text_format">WebAssemblyテキストフォーマットを理解する</a> を参照してください。</p>
</div>
<h2 id="Using_XMLHttpRequest">XMLHttpRequest を使用する</h2>
<p><code><a href="/ja/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> は Fetch よりやや古いですが、引き続き型付き配列を取得するために適切に使用することができます。繰り返しますが、モジュール名は <code>simple.wasm</code> とします:</p>
<ol>
<li>{{domxref("XMLHttpRequest()")}} インスタンスを生成して、{{domxref("XMLHttpRequest.open","open()")}} メソッドでリクエストをオープン、リクエストメソッドを <code>GET</code> に設定し、フェッチするためのパスを宣言します。</li>
<li>キーは {{domxref("XMLHttpRequest.responseType","responseType")}} を使用してレスポンスタイプを <code>'arraybuffer'</code> にすることです。</li>
<li>次に {{domxref("XMLHttpRequest.send()")}} を使用してリクエストします。</li>
<li>そのあと、ダウンロードが終了したときに {{domxref("XMLHttpRequest.onload", "onload")}} イベントハンドラから関数を実行します — この関数内で {{domxref("XMLHttpRequest.response", "response")}} プロパティから array buffer を取得し、Fetchで行ったように {{jsxref("WebAssembly.instantiate()")}} メソッドに渡します。</li>
</ol>
<p>最終的なコードは以下のようになります:</p>
<pre class="brush: js">request = new XMLHttpRequest();
request.open('GET', 'simple.wasm');
request.responseType = 'arraybuffer';
request.send();
request.onload = function() {
var bytes = request.response;
WebAssembly.instantiate(bytes, importObject).then(results => {
results.instance.exports.exported_func();
});
};</pre>
<div class="note">
<p><strong>注</strong>: 動作例は <a href="https://mdn.github.io/webassembly-examples/js-api-examples/xhr-wasm.html">xhr-wasm.html</a> を参照してください。</p>
</div>
|