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
|
---
title: Loading and running WebAssembly code
slug: WebAssembly/Loading_and_running
tags:
- JavaScript
- Traer
- WebAssembly
- XMLHttpRequest
- bytecode
translation_of: WebAssembly/Loading_and_running
---
<div>{{WebAssemblySidebar}}</div>
<p class="summary">Para utilizar WebAssembly en JavaScript, necesita primero jalar su módulo dentro de la memoria antes dela compilación/instanciación. Este artículo ofrece una referencia para mecanismos distintos que pueden traer el bytecode de WebAssembly, así como tener la forma de compilar/instanciarlo una vez que ya funciona.</p>
<h2 id="¿Cuáles_son_las_opciones">¿Cuáles son las opciones?</h2>
<p>WebAssembly no está integradon aún con la etiqueta <code><script type='module'></code> o con la directiva ES2015 <code>import</code>, así, no existe una forma para que el navegador busque sus módulos a partir de importaciones.</p>
<p>Los métodos anteriores {{jsxref("WebAssembly.compile")}}/{{jsxref("WebAssembly.instantiate")}} requieren que se creen un {{domxref("ArrayBuffer")}} que contenga su módulo binario WebAssembly después de buscar los bytes sin procesar, y luego los compila/instancia. Estos es análogo a la <code>new Function(string)</code>, excepto que estamos sustituyendo una cadena de caracteres (código fuente JavaScript) con una memoria intermedia (arreglo) de bytes (código fuente de WebAssembly).</p>
<p>Lo actual en métodos {{jsxref("WebAssembly.compileStreaming")}}/{{jsxref("WebAssembly.instantiateStreaming")}} es que son mucho más eficientes — desempeñan sus acciones directamente sobre flujos de bytes sin procesar (raw streams) originados en la red, suprimiendo la necesidad de tenerl el paso de {{domxref("ArrayBuffer")}}.</p>
<p>La pregunta ¿cómo hacemos para tener esos bytes dentro de la memoria intermedia (arreglo) y compilarlos? En la siguiente sección lo explicamos.</p>
<h2 id="Utilización_de_Fetch_Traer_a">Utilización de Fetch (Traer a)</h2>
<p><a href="/en-US/docs/Web/API/Fetch_API">Fetch</a> es una API moderna y conveniente para traer recursos de la red.</p>
<p>La manera más eficiente y rápida de traer un módulo wasm (WebAssembly Module) es utilizando el método actualizado {{jsxref("WebAssembly.instantiateStreaming()")}}, que puede generar una llamada al método <code>fetch()</code> como primer argumento y manejará la búsqueda, compilación e instanciación del módulo paso a paso, teniendo acceso a los bytes sin procesar mientras se transmiten (stream) del servidor:</p>
<pre class="brush: js notranslate">WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(results => {
// Hacemos algo con el resultado aquí!
});</pre>
<p>Si usamos el método anterior {{jsxref("WebAssembly.instantiate()")}} , que no trabaja sobre una transmisión (stream) directa, necesitaremos un paso adicional para convertir el byte code buscado a un {{domxref("ArrayBuffer")}}, como se muestra a continuación:</p>
<pre class="brush: js notranslate">fetch('module.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results => {
// Hacemos algo con el resultado aquí!
});</pre>
<h3 id="Más_allá_de_las_sobrecargas_de_instantiate">Más allá de las sobrecargas de instantiate()</h3>
<p>La función {{jsxref("WebAssembly.instantiate()")}} tiene dos formas de sobrecargar — la primera se muestra arriba, toma el byte code como argumento para compilar y regresa un compromiso de que resolverá un objeto que contenga tanto un módulo objeto compilado, como una instancia desarrollada de ello. El objeto se ve como lo siguiente:</p>
<pre class="brush: js notranslate">{
module : Module // El recién compilado objeto WebAssembly.Module,
instance : Instance // Una instancia nueva de WebAssembly.Instance del módulo}</pre>
<div class="note">
<p><strong>Nota</strong>: Generalmente solo nos preocupamos de la instancia, pero resulta útil tener el módulo en caso de que querramos almacenarlo temporalmente (cache), compartirlo con otro proceso o ventana vía <code><a href="/en-US/docs/Web/API/MessagePort/postMessage">postMessage()</a></code>, o simplemente crear mas instancias.</p>
</div>
<div class="note">
<p><strong>Nota</strong>: La segunda forma de sobrecarga utiliza un objeto del tipo {{jsxref("WebAssembly.Module")}} como argumento y regresa un compromiso directo conteniendo la instancia del objeto como resultado. Vea el <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate#Second_overload_example">Segundo ejemplo de sobrecarga</a>.</p>
</div>
<h3 id="Ejecutando_su_código_WebAssembly">Ejecutando su código WebAssembly </h3>
<p>Una vez que se tiene disponible la instancia WebAssembly en su código JavaScript, puede entonces comenzar a utilizar las funcionalidades de éste, que han sido exportadas vía la propiedad {{jsxref("WebAssembly.Instance/exports", "WebAssembly.Instance.exports")}}. Su código podría verse como lo que a continuación mostramos:</p>
<pre class="brush: js notranslate">WebAssembly.instantiateStreaming(fetch('myModule.wasm'), importObject)
.then(obj => {
// Llamada a una función exportada:
obj.instance.exports.exported_func();
// o acceso al contenido de la memoria exportada:
var i32 = new Uint32Array(obj.instance.exports.memory.buffer);
// o acceso a los elementos de una tabla exportada:
var table = obj.instance.exports.table;
console.log(table.get(0)());
})</pre>
<div class="note">
<p><strong>Nota</strong>: Para mayor información sobre como funciona la exportación de módulos WebAssembly, debes leer <a href="/en-US/docs/WebAssembly/Using_the_JavaScript_API">Utilización de la Interfaz (API) de WebAssembly JavaScript</a>, y <a href="/en-US/docs/WebAssembly/Understanding_the_text_format">Entendiendo el formato de texto en WebAssembly</a>.</p>
</div>
<h2 id="Utilizando_XMLHttpRequest">Utilizando XMLHttpRequest</h2>
<p><code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> es de alguna forma más viejo que Fetch, pero se puede utilizar aún para obtener un arreglo de tipos. De nuevo, los pasos para utilizarlo, asumiendo que nuestro módulo se llama <code>simple.wasm</code>:</p>
<ol>
<li>Crear una instancia nueva de {{domxref("XMLHttpRequest()")}} y utilizar su método {{domxref("XMLHttpRequest.open","open()")}} para abrir una petición, dejando el método de petición en <code>GET</code>, y declarando la ruta al alrchivo que queremos traer.</li>
<li>La parte clave de esto es poner el tipo de respuesta al uso de <code>'arraybuffer'</code> por medio de la propiedad {{domxref("XMLHttpRequest.responseType","responseType")}}.</li>
<li>Luego, enviar la petición utilizando {{domxref("XMLHttpRequest.send()")}}.</li>
<li>Cuando luego se utilice el manejador de evento {{domxref("XMLHttpRequest.onload", "onload")}} para invocar una función cuando la respuesta haya terminado de descargar — en esta función tomamos el arreglo de la propiedad {{domxref("XMLHttpRequest.response", "response")}} y luego lo mandamos a nuestro método {{jsxref("WebAssembly.instantiate()")}} como hicimos con Fetch.</li>
</ol>
<p>El código final queda:</p>
<pre class="brush: js notranslate">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>Nota</strong>: Puede ver un ejemplo de esta acción en <a href="https://mdn.github.io/webassembly-examples/js-api-examples/xhr-wasm.html">xhr-wasm.html</a>.</p>
</div>
|