aboutsummaryrefslogtreecommitdiff
path: root/files/pt-br/webassembly/using_the_javascript_api/index.html
blob: 8ff4be0f91a652af67a61c1729497cd1b4429862 (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
---
title: Usando a API JavaScript do WebAssembly
slug: WebAssembly/Using_the_JavaScript_API
tags:
  - API
  - Compilador
  - DevTools
  - JavaScript
  - WebAssembly
  - compilar
  - memoria
  - tabela
translation_of: WebAssembly/Using_the_JavaScript_API
original_slug: WebAssembly/Usando_a_API_JavaScript_do_WebAssembly
---
<div>{{WebAssemblySidebar}}</div>

<p class="summary">Se você já <a href="/en-US/docs/WebAssembly/C_to_wasm">compilou um módulo de outra linguagem utilizando ferramentas como o Emscripten</a>, ou <a href="/en-US/docs/WebAssembly/Loading_and_running">carregou e executou o código sozinho</a>, o próximo passo é aprender mais sobre o uso de outros recursos da API JavaScript do WebAssembly. Este artigo te ensina o que você precisará saber.</p>

<div class="note">
<p><strong>Nota</strong>: Se você não estiver familiarizado com os conceitos básicos mencionados neste artigo e precisar de mais explicação, leia <a href="/en-US/docs/WebAssembly/Concepts">WebAssembly concepts</a> primeiro, e depois volte aqui.</p>
</div>

<h2 id="Um_exemplo_simples">Um exemplo simples</h2>

<p>Vamos percorrer o passo a passo de um exemplo que explica como usar a API JavaScript do WebAssembly, e como usá-la para carregar um módulo wasm em uma página web.</p>

<div class="note">
<p><strong>Nota</strong>: Você pode encontrar o código de exemplo no nosso repositório di GitHub <a href="https://github.com/mdn/webassembly-examples">webassembly-examples</a>.</p>
</div>

<h3 id="Preparando_o_exemplo">Preparando o exemplo</h3>

<ol>
 <li>Primeiro precisamos de um módulo wasm! Pegue o nosso arquivo <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/simple.wasm">simple.wasm</a> e salve uma cópia em um novo diretório em sua máquina local.</li>
 <li>Depois, tenha certeza de que você está usando um browser com suporte ao WebAssembly. O Firefox 52+ e o Chrome 57+ já vem com WebAssembly habilitado por padrão.</li>
 <li>Depois, crie um arquivo html simples chamado <code>index.html</code> no mesmo diretório que seu arquivo wasm (você pode usar o nosso <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">template simples</a> caso você não tenha algum por aí).</li>
 <li>Agora, para ajudar a entender o que está acontecendo aqui, vamos olhar a representação textual do nosso módulo wasm (do qual também encontramos em <a href="/en-US/docs/WebAssembly/Text_format_to_wasm#A_first_look_at_the_text_format">Converting WebAssembly format to wasm</a>):
  <pre>(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "exported_func")
    i32.const 42
    call $i))</pre>
 </li>
 <li>Na segunda linha, você perceberá que o import tem um namespace de dois níveis — a função interna <code>$i</code> que é importada do <code>imports.imported_func</code>. Precisamos refletir esse namespace de dois níveis no JavaScript ao escrever o objeto que será importado no módulo wasm. Crie um elemento <code>&lt;script&gt;&lt;/script&gt;</code> no seu arquivo HTML, e adicione o seguinte código:
  <pre class="brush: js">var importObject = {
  imports: {
      imported_func: function(arg) {
        console.log(arg);
      }
    }
  };</pre>
 </li>
</ol>

<p>Conforme explicado acima, temos nossa função que será importada em <code>imports.imported_func</code>.</p>

<div class="note">
<p><strong>Nota</strong>: Isto poderia ser mais conciso usando <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">a sintaxe de arrow function do ES6</a>:</p>

<pre class="brush: js">var importObject = { imports: { imported_func: arg =&gt; console.log(arg) } };</pre>
</div>

<p>O estilo que você preferir fica a sua escolha.</p>

<h3 id="Carregando_e_utilizando_o_nosso_módulo_wasm">Carregando e utilizando o nosso módulo wasm</h3>

<p>Com o objeto que iremos importar preparado, vamos baixar o nosso arquivo wasm, torná-lo disponível em um array buffer, e em seguida fazer uso de sua função exportada.</p>

<p>Adicione o código abaixo no seu script:</p>

<pre class="brush: js">fetch('simple.wasm').then(response =&gt;
  response.arrayBuffer()
).then(bytes =&gt;
  WebAssembly.instantiate(bytes, importObject)
).then(results =&gt; {
  results.instance.exports.exported_func();
});</pre>

<div class="note">
<p><strong>Nota</strong>: Já explicamos com grandes detalhes como funciona essa síntaxe em <a href="/en-US/docs/WebAssembly/Loading_and_running#Using_Fetch">Loading and running WebAssembly code</a>. Volte lá e se atualize caso não se sinta confortável com o assunto.</p>
</div>

<p>O resultado liquido disto é que nós chamamos nossa função <code>exported_func</code> exportada pelo WebAssembly, que por sua vez chama a nossa função JavaScript importada <code>imported_func</code>, que mostra no console o valor fornecido (42) dentro da instância do WebAssembly. Se você salvar seu código de exemplo agora e carregá-lo em um browser que suporta WebAssembly, você verá isso em ação!</p>

<div class="note">
<p><strong>Nota</strong>: O WebAssembly está habilitado por padrão no Firefox 52+, no Chrome 57+ e no Opera mais recente (você também pode executar código wasm no Firefox 47+ habilitando a flag <code>javascript.options.wasm</code> em <em>about:config</em>, ou no Chrome (51+) e no Opera (38+) indo em <em>chrome://flags</em> e habilitando a flag <em>Experimental WebAssembly</em> .)</p>
</div>

<p>Este exemplo é longo e um pouco complicado que alcança muito pouco, mas serve para mostrar o que é possível — usando código WebAssembly junto com JavaScript em suas aplicações web. Como já dissemos em outro lugar, o WebAssembly não pretende substituir o JavaScript; ambos podem trabalhar juntos, juntando forças.</p>

<h3 id="Visualizando_o_wasm_no_developer_tools">Visualizando o wasm no developer tools</h3>

<p>No Firefox 54+, o painel Debugger do Developer Tool consegue exibir a representação textual do qualquer código wasm inserido em uma página web. Para visualizá-lo, abra o painel Debugger e clique em “xxx &gt; wasm”.</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/14655/wasm-debugger-output.png" style="display: block; height: 354px; margin: 0px auto; width: 1026px;"></p>

<p>Muito em breve no Firefox, além de visualizar o WebAssembly em seu formato textual, os desenvolvedores serão capazes de depurar (colocar breakpoints, inspecionar o callstack, etc.) o WebAssembly utilizando o formato textual. Assista o vídeo  <span class="watch-title" dir="ltr" id="eow-title" title="WebAssembly debugging with Firefox DevTools"><a href="https://www.youtube.com/watch?v=R1WtBkMeGds">WebAssembly debugging with Firefox DevTools</a> </span>para ter uma prévia.</p>

<h2 id="Memória">Memória</h2>

<p>No modelo de memória de baixo nível do WebAssembly, a memória é representada como uma faixa contínua de bytes não tipados chamados de <a href="http://webassembly.org/docs/semantics/#linear-memory">Memória Linear</a> que são lidos e escritos por <a href="http://webassembly.org/docs/semantics/#linear-memory-accesses">instruções de carga e armazenamento</a> dentro do módulo. Neste modelo de memória, qualquer carga ou armazenamento pode acessar qualquer byte na memória linear inteira, o que é necessário para representar fielmente conceitos de C/C++ como ponteiros.</p>

<p>Ao contrário de um programa C/C++ nativo, contudo, onde a coleção de memória disponível se estende por todo o processo, a memória que é acessível por uma instância de WebAssembly em particular se limita a uma única — e potencialmente muito pequena — coleção contida por um objeto do tipo WebAssembly Memory.  Isto possibilita que uma única aplicação web utilize diversas bibliotecas independentes — cada uma das quais estiverem utilizando o WebAssembly internamente — para ter memórias separadas que são totalmente isoladas umas das outras.</p>

<p>In JavaScript, a Memory instance can be thought of as a resizable ArrayBuffer and, just as with ArrayBuffers, a single web app can create many independent Memory objects.  You can create one using the {{jsxref("WebAssembly.Memory()")}} constructor, which takes as arguments an initial size and (optionally) a maximum size.</p>

<p>Let’s start exploring this by looking at a quick example.</p>

<ol>
 <li>
  <p>Create another new simple HTML page (copy our <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">simple template</a>) and call it <code>memory.html</code>. Add a <code>&lt;script&gt;&lt;/script&gt;</code> element to the page.</p>
 </li>
 <li>
  <p>Now add the following line to the top of your script, to create a memory instance:</p>

  <pre class="brush: js">var memory = new WebAssembly.Memory({initial:10, maximum:100});</pre>

  <p>The unit of <code>initial</code> and <code>maximum</code> is WebAssembly pages — these are fixed to 64KB in size. This means that the above memory instance has an initial size of 640KB, and a maximum size of 6.4MB.</p>

  <p>WebAssembly memory exposes its bytes by simply providing a buffer getter/setter that returns an ArrayBuffer. For example, to write 42 directly into the first word of linear memory, you can do this:</p>

  <pre class="brush: js">new Uint32Array(memory.buffer)[0] = 42;</pre>

  <p>You can then return the same value using:</p>

  <pre class="brush: js">new Uint32Array(memory.buffer)[0]</pre>
 </li>
 <li>
  <p>Try this now in your demo — save what you’ve added so far, load it in your browser, then try entering the above two lines in your JavaScript console.</p>
 </li>
</ol>

<h3 id="Growing_memory">Growing memory</h3>

<p>A memory instance can be grown by calls to {{jsxref("Memory.prototype.grow()")}}, where again the argument is specified in units of WebAssembly pages:</p>

<pre class="brush: js">memory.grow(1);</pre>

<p>If a maximum value was supplied upon creation of the memory instance, attempts to grow past this maximum will throw a {{jsxref("WebAssembly.RangeError")}} exception. The engine takes advantage of this supplied upper-bounds to reserve memory ahead of time, which can make resizing more efficient.</p>

<p>Note: Since an {{domxref("ArrayBuffer")}}’s byteLength is immutable, after a successful {{jsxref("Memory.prototype.grow()")}} operation the buffer getter will return a new ArrayBuffer object (with the new byteLength) and any previous ArrayBuffer objects become “detached”, or disconnected from the underlying memory they previously pointed to.</p>

<p>Just like functions, linear memories can be defined inside a module or imported. Similarly, a module may also optionally export its memory. This means that JavaScript can get access to the memory of a WebAssembly instance either by creating a new <code>WebAssembly.Memory</code> and passing it in as an import or by receiving a Memory export (via <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports">Instance.prototype.exports</a></code>).</p>

<h3 id="More_involved_memory_example">More involved memory example</h3>

<p>Let’s make the above assertions clearer by looking at a more involved memory example — a WebAssembly module that sums an array of integers. You can find this at <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/memory.wasm">memory.wasm.</a></p>

<ol>
 <li>
  <p>make a local copy of <code>memory.wasm</code> in the same directory as before.</p>

  <div class="note">
  <p><strong>Note</strong>: You can see the module’s text representation at <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.wat">memory.wat</a>.</p>
  </div>
 </li>
 <li>
  <p>Go back to your <code>memory.html</code> sample file, and fetch, compile, and instantiate your wasm module as before — add the following to the bottom of your script:</p>

  <pre class="brush: js">fetch('memory.wasm').then(response =&gt;
  response.arrayBuffer()
).then(bytes =&gt;
  WebAssembly.instantiate(bytes)
).then(results =&gt; {
  // add your code here
});</pre>
 </li>
 <li>
  <p>Since this module exports its memory, given an Instance of this module called instance we can use an exported function <code>accumulate()</code> to create and populate an input array directly in the module instance’s linear memory (<code>mem</code>). Add the following into your code, where indicated:</p>

  <pre class="brush: js">var i32 = new Uint32Array(results.instance.exports.mem.buffer);
for (var i = 0; i &lt; 10; i++) {
  i32[i] = i;
}

var sum = results.instance.exports.accumulate(0, 10);
console.log(sum);</pre>
 </li>
</ol>

<p>Note how we create the {{domxref("Uint32Array")}} view on the Memory object’s buffer (<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer">Memory.prototype.buffer</a></code>), not on the Memory itself.</p>

<p>As importações de memória funcionam como importações de função, apenas objetos de memória são passados ​​como valores em vez de funções JavaScript. As importações de memória são úteis por dois motivos:</p>

<ul>
 <li>Eles permitem que o JavaScript busque e crie o conteúdo inicial da memória antes ou simultaneamente com a compilação do módulo.</li>
 <li>Eles permitem que um único objeto Memory seja importado por várias instâncias do módulo, o que é um bloco de construção crítico para implementar a vinculação dinâmica no WebAssembly.</li>
</ul>

<div class="note">
<p><strong>Note</strong>: You can find our complete demo at <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.html">memory.html</a> (<a href="https://mdn.github.io/webassembly-examples/js-api-examples/memory.html">see it live also</a>) — this version uses the <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code> function.</p>
</div>

<h2 id="Tables">Tables</h2>

<p>A WebAssembly Table is a resizable typed array of <a href="https://en.wikipedia.org/wiki/Reference_(computer_science)">references</a> that can be accessed by both JavaScript and WebAssembly code.  While Memory provides a resizable typed array of raw bytes, it is unsafe for references to be stored in a Memory since a reference is an engine-trusted value whose bytes must not be read or written directly by content for safety, portability, and stability reasons.</p>

<p>Tables have an element type, which limits the types of reference that can be stored in the table.  In the current iteration of WebAssembly, there is only one type of reference needed by WebAssembly code — functions — and thus only one valid element type.  In future iterations, more element types will be added.</p>

<p>Function references are necessary to compile languages like C/C++ that have function pointers.  In a native implementation of C/C++, a function pointer is represented by the raw address of the function’s code in the process’s virtual address space and so, for the safety reasons mentioned above, cannot be stored directly in linear memory.  Instead, function references are stored in a table and their indexes, which are integers and can be stored in linear memory, are passed around instead.</p>

<p>When the time comes to call a function pointer, the WebAssembly caller supplies the index, which can then be safety bounds checked against the table before indexing and calling the indexed function reference.  Thus, tables are currently a rather low-level primitive used to compile low-level programming language features safely and portably.</p>

<p>Tables can be mutated via <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set">Table.prototype.set()</a></code>, which updates one of the values in a table, and <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow">Table.prototype.grow()</a></code>, which increases the number of values that can be stored in a table.  This allows the indirectly-callable set of functions to change over time, which is necessary for <a href="http://webassembly.org/docs/dynamic-linking/">dynamic linking techniques</a>.  The mutations are immediately accessible via <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code> in JavaScript, and to wasm modules.</p>

<h3 id="A_table_example">A table example</h3>

<p>Let’s looking at an simple table example — a WebAssembly module that creates and exports a table with two elements: element 0 returns 13 and element 1 returns 42. You can find this at <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/table.wasm">table.wasm</a>.</p>

<ol>
 <li>
  <p>Make a local copy of <code>table.wasm</code> in a new directory.</p>

  <div class="note">
  <p><strong>Note</strong>: You can see the module’s text representation at <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.wat">table.wat</a>.</p>
  </div>
 </li>
 <li>
  <p>Create a new copy of our <a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">HTML template</a> in the same directory and call it <code>table.html</code>.</p>
 </li>
 <li>
  <p>As before, fetch, compile, and instantiate your wasm module — add the following into a {{htmlelement("script")}} element at the bottom of your HTML body:</p>

  <pre class="brush: js">fetch('table.wasm').then(response =&gt;
  response.arrayBuffer()
).then(bytes =&gt;
  WebAssembly.instantiate(bytes)
).then(results =&gt; {
  // add your code here
});</pre>
 </li>
 <li>
  <p>Now let’s access the data in the tables — add the following lines to your code in the indicated place:</p>

  <pre class="brush: js">var tbl = results.instance.exports.tbl;
console.log(tbl.get(0)());  // 13
console.log(tbl.get(1)());  // 42</pre>
 </li>
</ol>

<p>This code accesses each function reference stored in the table in turn, and instantiates them to print the values they hold to the console — note how each function reference is retrieved with a <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code> call, then we add an extra set of parentheses on the end to actually invoke the function.</p>

<div class="note">
<p><strong>Note</strong>: You can find our complete demo at <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.html">table.html</a> (<a href="https://mdn.github.io/webassembly-examples/js-api-examples/table.html">see it live also</a>) — this version uses the <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code> function.</p>
</div>

<h2 id="Multiplicity">Multiplicity</h2>

<p>Now we’ve demonstrated usage of the main key WebAssembly building blocks, this is a good place to mention the concept of multiplicity. This provides WebAssembly with a multitude of advances in terms of architectural efficiency:</p>

<ul>
 <li>One module can have N Instances, in the same way that one function literal can produce N closure values.</li>
 <li>One module instance can use 0–1 memory instances, which provide the "address space" of the instance. Future versions of WebAssembly may allow 0–N memory instances per module instance (see <a href="http://webassembly.org/docs/future-features/#multiple-tables-and-memories">Multiple Tables and Memories</a>).</li>
 <li>One module instance can use 0–1 table instances — this is the "function address space" of the instance, used to implement C function pointers. Future versions of WebAssembly may allow 0–N table instances per module instance in the future.</li>
 <li>One memory or table instance can be used by 0–N module instances — these instances all share the same address space, allowing <a href="http://webassembly.org/docs/dynamic-linking">dynamic linking</a>.</li>
</ul>

<p>You can see multiplicity in action in our Understanding text format article — see the Mutating tables and dynamic linking section (TBD).</p>

<h2 id="Summary">Summary</h2>

<p>This article has taken you through the basics of using the WebAssembly JavaScript API to include a WebAssembly module in a JavaScript context and make use of its functions, and how to use WebAssembly memory and tables in JavaScript. We also touched on the concept of multiplicity.</p>

<h2 id="See_also">See also</h2>

<ul>
 <li><a href="http://webassembly.org/">webassembly.org</a></li>
 <li><a href="/en-US/docs/WebAssembly/Concepts">WebAssembly concepts</a></li>
</ul>