Согласно официальному сайту, WebAssembly описан ниже -

WebAssembly (сокращенно Wasm) - это двоичный формат инструкций для виртуальной машины на основе стека. Wasm разработан как переносимая цель компиляции для языков программирования, позволяющая развертывать в Интернете клиентские и серверные приложения.

В рамках этой статьи я предполагаю, что вы знаете, что такое WebAssembly и чего он стремится достичь. Вы можете прочитать больше об этом здесь".

Заявление об ограничении ответственности: я не претендую на звание эксперта по WebAssembly. Большинство моих знаний об этой статье взяты из Learn WebAssembly - Майка Рурка, https://emscripten.org/, WebAssembly on MDN. Если вы обнаружите какие-либо ошибки в статье ниже, сообщите мне! Я просто учусь и играю с этим.

У нас есть две спецификации API для взаимодействия с модулями WebAssembly - интерфейс JavaScript WebAssembly (API JavaScript) и веб-API WebAssembly.

Сегодня мы поговорим о различных способах загрузки модулей .wasm в наш код JavaScript. Вам необходимо загрузить и установить Emscripten, чтобы следовать приведенным ниже примерам.

Использование объекта WebAssembly

Мы собираемся использовать программу на C ++, чтобы продемонстрировать то же самое. Ниже приведена простая функция для сложения двух чисел -

Во-первых, давайте скомпилируем наш main.cc в модуль .wasm без создания связующего кода, предоставляемого Emscripten.

$ em++ -std=c++11 main.cc -Os -s WASM=1 -s SIDE_MODULE=1 -s BINARYEN_ASYNC_COMPILATION=0 -o main.wasm

Для загрузки и использования модуля WebAssembly в JavaScript необходимо выполнить следующие три шага:

  • Сначала получите .wasm байт и преобразуйте его в типизированный массив или ArrayBuffer
  • Скомпилируйте байты в WebAssembly.Module
  • Создайте экземпляр WebAssembly.Module

API JavaScript имеет глобальный объект WebAssembly, доступный в браузере. Он действует как пространство имен для всех функций, связанных с WebAssembly. Он имеет следующие статические методы -

  • WebAssembly.instantiate() используется для одновременной компиляции и создания экземпляров байтов. Он возвращает как Module, так и первое Instance.
  • WebAssembly.instantiateStreaming() выполняет те же функции, что и instantiate (), но использует потоковую передачу для компиляции и создания экземпляра модуля, что исключает промежуточный этап преобразования байтов .wasm в ArrayBuffer.
  • WebAssembly.compile() только компилирует модуль WebAssembly, но не создает его экземпляр
  • WebAssembly.compileStreaming() также компилирует только модуль WebAssembly, но использует потоковую передачу, аналогичную instantiateStreaming (), что исключает промежуточный этап.
  • WebAssembly.validate() проверяет двоичный код WebAssembly, чтобы убедиться, что байты действительны, и возвращает истину или ложь.

Использование WebAssembly.instantiate ()

Создайте index.html file и добавьте тег скрипта, в который мы будем извлекать наш файл main.wasm. Здесь мы будем использовать fetch API, но вы также можете использовать XMLHttpRequest (прочтите, как его использовать здесь). Затем мы создаем ArrayBuffer ответа и инстанцируем его с помощью WebAssembly.instantiate (). resultсодержит объект экземпляра, на который нам нужно ссылаться для вызова экспортируемых функций из модуля.

Потоковая передача модуля WebAssembly

Новые методы _16 _ / _ 17_ намного более эффективны - они извлекают, компилируют / инстанцируют модуль за один шаг, прямо из необработанного байт-кода, устраняя необходимость в шаге ArrayBuffer.

Использование объекта модуля Emscripten

В этом примере мы будем использовать следующий файл C ++ -

EMSCRIPTEN_KEEPALIVE заставляет LLVM не устранять мертвый код функции. Мы заключаем нашу функцию в блок extern «C», чтобы избежать искажения имени, которое происходит в C ++.

Теперь скомпилируйте его в main.wasm и сгенерируйте также javascript-код связующего кода -

$ em++ -std=c++11 main.cc -o main.js -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'

Приведенная выше команда сообщает Emscripten о необходимости создания main.wasm и main.js, которые содержат объект Emscriptens Module. Emscripten предоставляет две функции для вызова скомпилированных функций C / C ++ из JavaScript: ccall () и cwrap (). EXTRA_EXPORTED_RUNTIME_METHODS экспортирует функции ccall и cwrap, к которым затем можно получить доступ из объекта Module.

Объект Module доступен глобально после включения main.js в наш файл index.html.

Модуль предоставляет некоторые полезные функции "из коробки", которые в противном случае потребовали бы специальной реализации в WebAssembly. Модуль Emscripten можно рассматривать как комбинацию объектов модуля и экземпляра WebAssembly, которые присутствуют в объекте результата, возвращаемом функцией создания экземпляра WebAssembly.

Module.onRuntimeInitialized() вызывается, когда среда выполнения полностью инициализирована, то есть когда скомпилированный код можно безопасно запускать, то есть после завершения любых асинхронных операций запуска (таких как асинхронная компиляция WebAssembly, предварительная загрузка файлов и т. Д.). Если вы не используете это, вы можете столкнуться со следующей ошибкой -

Uncaught RuntimeError: abort(Assertion failed: native function `Sum` called before runtime initialization) at Error

Module.cwrap (identify, returnType, argTypes) возвращает встроенную оболочку JavaScript для нашей экспортированной функции C ++. Его можно повторно использовать столько раз, сколько необходимо, тогда как Module.ccall (identity, returnType, argTypes, args, opts) выполняет скомпилированную функцию C ++ из JavaScript и возвращает результат.

Спасибо за чтение! В следующем посте я напишу больше о том, как вызывать функции JavaScript в нашем C / C ++ с помощью Emscripten.