Загрузка и запуск кода WebAssembly
==================================

Чтобы использовать WebAssembly в JavaScript, сначала нужно загрузить модуль в память перед компиляцией/созданием экземпляра. Эта статья содержит справочную информацию о различных механизмах, которые можно использовать для получения байт-кода WebAssembly, а также о том, как скомпилировать/создать экземпляр, а затем запустить его.

Какие есть варианты?
--------------------

WebAssembly ещё не интегрирована с `<script type='module'>` или ES2015 оператором `import`, поэтому не существует пути, позволяющего использовать модули загрузки браузера для использования импорта.

Старые методы `WebAssembly.compile`/`WebAssembly.instantiate` (en-US) требуют создания `ArrayBuffer`, содержащего двоичный файл модуля WebAssembly после загрузки необработанных байтов, а затем скомпилировать/создать его экземпляр. Это аналог `new Function(string)`, за исключением того, что мы заменяем строку символов (исходный код JavaScript) буфером байтов массива (исходный код WebAssembly).

Более новые методы `WebAssembly.compileStreaming`/`WebAssembly.instantiateStreaming` (en-US) намного эффективнее - они выполняют свои действия непосредственно с необработанным потоком байтов, поступающих из сети, избавление от необходимости шага `ArrayBuffer`.

Итак, как мы можем получить эти байты в буфер массива и скомпилировать? Следующие разделы объясняют.

Используя Fetch
---------------

Fetch - это удобный современный API для извлечения сетевых ресурсов.

Самый быстрый и эффективный способ получить модуль wasm - использовать более новый метод `WebAssembly.instantiateStreaming()` (en-US), который может принять вызов `fetch()` в качестве первого аргумента и будет обрабатывать загрузку, компиляцию и создание экземпляра модуля за один шаг, получая доступ к необработанному байтовому коду при его потоковой передаче с сервера:


```js
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
  (results) => {
    // Do something with the results!
  },
);
```


Если бы мы использовали более старый метод `WebAssembly.instantiate()` (en-US), который не работает в прямом потоке, нам потребовался бы дополнительный шаг преобразования преобразованного байт-кода в `ArrayBuffer`, вот так:


```js
fetch("module.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((results) => {
    // Do something with the results!
  });
```

### Помимо перегрузок instantiate()

Функция `WebAssembly.instantiate()` (en-US) имеет две формы перегрузки - та, что показана выше, принимает байт-код для компиляции в качестве аргумента и возвращает `Promise`, которое разрешается для объекта, содержащего оба объекта скомпилированного модуля, и экземпляр этого. Объект выглядит так:


```js
{
  module: Module; // The newly compiled WebAssembly.Module object,
  instance: Instance; // A new WebAssembly.Instance of the module object
}
```


**Примечание:** Обычно мы заботимся только об экземпляре, но полезно иметь модуль на тот случай, если мы хотим его кешировать, поделиться им с другим работником или окном через `postMessage()` (en-US), или просто создать больше экземпляров.

**Примечание:** Вторая форма перегрузки принимает в качестве аргумента объект `WebAssembly.Module` (en-US) и возвращает `Promise`, непосредственно содержащее объект экземпляра, в качестве результата. См. Второй пример перегрузки (en-US).

### Выполнение вашего кода WebAssembly

Когда у вас есть экземпляр WebAssembly, доступный в вашем JavaScript, вы можете начать использовать его возможности, которые были экспортированы через свойство `WebAssembly.Instance.exports` (en-US). Ваш код может выглядеть примерно так:


```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)());
  },
);
```


**Примечание:** Для получения дополнительной информации о том, как работает экспорт из модуля WebAssembly, ознакомьтесь с разделами Использование JavaScript API WebAssembly, и Понимание текстового формата WebAssembly.

Используя XMLHttpRequest
------------------------

`XMLHttpRequest` несколько старше, чем Fetch, но всё же может успешно использоваться для получения типизированного массива. Опять же, если предположить, что наш модуль называется `simple.wasm`:

1. Создайте новый экземпляр `XMLHttpRequest()` и используйте его метод `open()` для открытия запроса, задав для метода запроса значение `GET` и указав путь к файлу, который мы хотим получить.
2. Ключевой частью этого является установка типа ответа `'arraybuffer'` с помощью свойства `responseType`.
3. Затем отправьте запрос с помощью `XMLHttpRequest.send()`.
4. Затем мы используем обработчик событий `onload` для вызова функции после завершения загрузки ответа - в этой функции мы получаем буфер массива из `response` и затем передайте это в наш метод `WebAssembly.instantiate()` (en-US), как мы это делали с Fetch.

Финальный код выглядит так:


```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();
  });
};
```


**Примечание:** вы можете увидеть пример этого в действии в xhr-wasm.html.