Книга «WebAssembly в действии»

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
image Привет, Хаброжители! Создавайте высокопроизводительные браузерные приложения, не полагаясь на один только JavaScript! Компилируясь в бинарный формат WebAssembly, ваш код на C, C++ или Rust будет работать в браузере с оптимальной скоростью. WebAssembly обеспечивает большую скорость, возможности повторного использования существующего кода и доступ к новым и более быстрым библиотекам. Кроме того, при необходимости вы можете настроить взаимодействие с JavaScript.

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

Создание модуля WebAssembly, вызывающего JavaScript



В главе 4 вы создали модуль WebAssembly, который вызывал JavaScript-код с помощью вспомогательной функции ccall из Emscripten. Буфер передавался в качестве параметра функции модуля, чтобы в случае возникновения проблемы можно было вернуть сообщение об ошибке, поместив его в буфер. Если возникает проблема, то JavaScript считывает строку из памяти модуля и затем отображает сообщение пользователю, как показано на рис. 5.1.

Представьте, что вместо передачи буфера функции модуля в случае возникновения проблемы модуль может просто передать сообщение об ошибке непосредственно в ваш JavaScript-код, как показано на рис. 5.2.

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

1. Использовать макросы Emscripten. К ним относятся серия макросов emscripten_run_script, макрос EM_JS и серия макросов EM_ASM.

2. Добавить собственный JavaScript-код в файл JavaScript в Emscripten, который можно использовать напрямую.

3. Задействовать указатели на функции, в которых код JavaScript указывает функцию, вызываемую модулем. Мы рассмотрим этот подход в главе 6.

image


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

1.Макросы Emscripten могут быть весьма полезны при отладке или когда нужно только взаимодействие с кодом JavaScript напрямую. По мере увеличения сложности кода макроса или количества взаимодействий с JavaScript вы можете рассмотреть возможность отделения кода макроса от кода на C или C++.. Это следует сделать, чтобы упростить сопровождение кода и вашего модуля, и веб-страницы.

Когда используются серии макросов EM_JS и EM_ASM, на самом деле компилятор Emscripten создает необходимые функции и добавляет их в сгенерированный файл JavaScript в Emscripten. Вызывая макросы, модуль WebAssembly в действительности вызывает сгенерированные функции JavaScript.

СПРАВКА
Более подробную информацию о макросах Emscripten, в том числе о том, как их использовать, можно найти в приложении В.


2. Как вы увидите в данной главе, вызывать JavaScript напрямую несложно, и это несколько упростит JavaScript вашего сайта. Если вы планируете вызывать функции из функции JavaScript, размещенной в сгенерированном Emscripten JavaScript-коде, то вам необходимо иметь какое-то представление об основном коде JavaScript. Если вы поставляете модуль третьей стороне, то потребуются четкие инструкции по правильной настройке модуля, чтобы не было ошибок, — например, о том, что функция не существует.

ПРЕДУПРЕЖДЕНИЕ
Если вы планируете использовать этот подход вместе с Node.js, то JavaScript-код, который вы добавляете в сгенерированный файл JavaScript, должен быть автономным. Работа с Node.js рассматривается более подробно в главе 10, но, по сути, из-за того, как Node.js загружает файл JavaScript в Emscripten, код в этом файле не может вызывать ваш основной JavaScript-код.


3. В главе 6 вы увидите, что использование указателей на функции дает гораздо больше гибкости, поскольку модулю не нужно знать, какие функции существуют в вашем JavaScript-коде. Вместо этого модуль просто вызовет предоставленную JavaScript-функцию. Дополнительная гибкость указателей на функции связана с немного большей сложностью, поскольку такой подход требует большего количества кода на JavaScript, чтобы все работало правильно.

Вместо того чтобы позволять Emscripten создавать функции JavaScript с помощью макросов, вы можете определить собственный JavaScript, который будет включен в файл JavaScript в Emscripten. Мы изучим такой подход в данной главе.

В рамках этого сценария мы изменим модуль валидации, созданный в главе 4, чтобы при возникновении проблемы при валидации сообщение об ошибке не передавалось обратно вызывающей функции с помощью параметра.. Вместо этого вы сделаете следующее (рис. 5.3).

1. Если была найдена проблема с пользовательским вводом, то пусть модуль вызовет функцию JavaScript, которую вы поместите в созданный Emscripten файл JavaScript.

2. Функция JavaScript будет принимать указатель от модуля и считывать сообщение об ошибке из памяти модуля.

3. Затем она передаст сообщение в основной JavaScript веб-страницы, где будет обработано обновление пользовательского интерфейса с полученной ошибкой.

image


Использование C или C++ для создания модуля со связующим кодом EMSCRIPTEN

Вернемся к логике валидации в C++, созданной в главе 4, и изменим ее так, чтобы она могла взаимодействовать с кодом на JavaScript. Добавим стандартную библиотеку C и вспомогательные функции Emscripten — это рекомендуемый способ создания модуля, предназначенного для использования в производственной среде. Позже в данной главе мы рассмотрим и другой подход к созданию модуля WebAssembly, который не включает стандартную библиотеку C или вспомогательные функции Emscripten.

Как показано на рис. 5.4, шаги по созданию модуля будут аналогичны шагам в главе 4.

1. Измените код на C++ так, чтобы он больше не получал строковый буфер и вместо этого вызывал функцию JavaScript в случае проблемы с валидацией.

2. Определите JavaScript-код, который нужно добавить в созданный Emscripten файл JavaScript.

3. Дайте Emscripten команду сгенерировать связующие файлы WebAssembly и JavaScript.

4. Скопируйте созданные файлы для использования в браузере.

5. Создайте веб-страницу, а затем напишите JavaScript-код, необходимый для взаимодействия с модулем WebAssembly.

image


Внесение изменений в код на C++

На рис. 5.5 видно, что первый шаг процесса — изменение кода на C++, чтобы он больше не получал строковый буфер. Вместо этого код вызовет функцию JavaScript, передав ей сообщение об ошибке при обнаружении проблемы с валидацией.

image


В папке WebAssembly создайте папку Chapter 5\5.1.1 EmJsLibrary\source\ для файлов, которые будут использоваться в этом подразделе. Скопируйте файл validate.cpp из папки WebAssembly\Chapter 4\4.1 js_plumbing\source\ в новую папку source. Откройте файл validate.cpp в своем любимом редакторе.

Сейчас вы измените код C++ так, чтобы вызвать функцию, определенную в JavaScript. Поскольку функция не является частью кода на C++, нужно сообщить компилятору о сигнатуре функции, добавив ключевое слово extern перед сигнатурой. Это позволяет компилировать код C++, ожидая, что функция будет доступна при запуске кода. Когда компилятор Emscripten видит сигнатуру функции, он создает для нее запись импорта в модуле WebAssembly. При создании экземпляра модуля фреймворк WebAssembly увидит запрошенный импорт и будет ожидать, что в JavaScript-файле будет предоставлена соответствующая функция.

Будущая функция в JavaScript принимает указатель const char* для параметра, который будет хранить сообщение об ошибке, если возникнет проблема с проверкой. Функция не возвращает значение. Чтобы определить сигнатуру функции, добавьте следующую строку кода в блок extern «C» и перед функцией ValidateValueProvided в файле validate.cpp:

extern void UpdateHostAboutError(const char* error_message);


Поскольку вы больше не собираетесь передавать буфер в модуль, необходимо удалить параметры char* return_error_message из функций. Кроме того, любой код, вызывающий strcpy для копирования сообщения об ошибке в буфер, теперь должен будет вместо этого вызвать функцию UpdateHostAboutError.

Измените функцию ValidateValueProvided, убрав параметр return_error_message, и добавьте вызов функции UpdateHostAboutError, а не strcpy, как показано ниже:

image


Подобно функции ValidateValueProvided, измените функцию ValidateName, чтобы она больше не получала параметр return_error_message, и удалите его из вызова функции ValidateValueProvided. Измените код, чтобы теперь сообщение об ошибке передавалось в функцию UpdateHostAboutError вместо использования strcpy, как показано ниже:

image


В функции IsCategoryIdInArray никаких изменений не требуется.

Наконец, необходимо внести те же изменения, что и для функций ValidateValueProvided и ValidateName, в функцию ValidateCategory, как показано в листинге 5.1.

image

image

Создание кода на JavaScript и добавление его в сгенерированный Emscripten JavaScript-файл

После того как код на C++ будет изменен, можно сделать следующий шаг — создать код на JavaScript и добавить его в JavaScript-файл, созданный Emscripten (рис. 5.6).

image


При написании кода на JavaScript, который будет включен в созданный Emscripten JavaScript-файл, модуль WebAssembly создается немного другим способом. В этом случае вы определите свою функцию UpdateHostAboutError в JavaScript до того, как дадите Emscripten указание скомпилировать код C++, поскольку с помощью компилятора Emscripten вы можете объединить ваш JavaScript-код с остальной частью JavaScript-кода, генерируемого Emscripten.

Чтобы ваш JavaScript был включен в созданный Emscripten JavaScript-файл, необходимо добавить его в объект LibraryManager.library в Emscripten; для этого можно использовать функцию mergeInto в Emscripten, которая принимает два параметра:

— объект, к которому нужно добавить свойства, — в данном случае объект LibraryManager.library;

— объект, свойства которого будут скопированы в первый объект, — в нашем случае ваш код на JavaScript.

Вы создадите JavaScript-объект, который будет содержать свойство UpdateHostAboutError; значение его — функция, получающая указатель на сообщение об ошибке. Функция считывает строку из памяти модуля с помощью вспомогательной функции в Emscripten — UTF8ToString — и затем вызывает JavaScript-функцию setErrorMessage, которая является частью основного кода JavaScript вашей веб-страницы.

В папке WebAssembly\Chapter 5\5.1.1 EmJsLibrary\source\ создайте файл mergeinto.js, откройте его в своем любимом редакторе и добавьте следующий фрагмент кода:

image


Компиляция кода в модуль WebAssembly

Изменив код на C++ и создав функцию JavaScript, которую нужно включить в JavaScript-файл, созданный Emscripten, можно сделать следующий шаг. Как показано на рис. 5.7, на данном этапе Emscripten скомпилирует код в модуль WebAssembly. Кроме того, Emscripten получит указание добавить код из вашего файла mergeinto.js в сгенерированный файл JavaScript.

image


Чтобы дать компилятору Emscripten указание включить ваш код на JavaScript в сгенерированный JavaScript-файл, нужно использовать флаг --js-library, за которым следует путь к добавляемому файлу. Чтобы быть уверенными в том, что вспомогательные функции Emscripten, необходимые вашему коду на JavaScript, включены в сгенерированный JavaScript-файл, вы должны указать их при компиляции кода на C++, добавив их в массив параметра EXTRA_EXPORTED_RUNTIME_METHODS. Укажите следующие вспомогательные функции Emscripten:

— ccall — используется JavaScript-кодом веб-страницы для вызова модуля;

— UTF8ToString — применяется JavaScript-кодом, который вы написали в файле mergeinto.js, для чтения строк из памяти модуля.

Чтобы скомпилировать код в модуль WebAssembly, откройте командную строку, перейдите в папку, в которой вы сохранили файлы validate.cpp и mergeinto.js, и выполните следующую команду:
emcc validate.cpp --js-library mergeinto.js
➥ -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','UTF8ToString']
➥ -o validate.js


Если вы откроете сгенерированный Emscripten файл JavaScript, validate.js, и выполните поиск функции UpdateHostAboutError, то увидите, что функция, которую вы сейчас определили, является частью сгенерированного JavaScript-файла:

function _UpdateHostAboutError(errorMessagePointer) {
setErrorMessage(Module.UTF8ToString(errorMessagePointer));
}


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

Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — WebAssembly

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Источник: https://habr.com/ru/company/piter/blog/586692/


Интересные статьи

Интересные статьи

Привет, Хаброжители! Мы сдали в типографию новую книгу Романа Зыкова rzykov. Она предназначена для думающих читателей, которые хотят попробовать свои силы в области анализа данных и созд...
Привет, Хаброжители! Книга Джейсона Грегори не случайно является бестселлером.Двадцать лет работы автора над первоклассными играми в Midway, Electronic Arts и Naughty Dog позволяют подел...
Привет, Хаброжители! Познакомьтесь с возможностями программирования Android на языке Kotlin! Множество примеров приложений с четкими объяснениями ключевых концепций и API позволят легко ...
В 1С Битрикс есть специальные сущности под названием “Информационные блоки, сокращенно (инфоблоки)“, я думаю каждый с ними знаком, но не каждый понимает, что это такое и для чего они нужны
Практически все коммерческие интернет-ресурсы создаются на уникальных платформах соответствующего типа. Среди них наибольшее распространение получил Битрикс24.