WebAssembly – это формат двоичных команд и виртуальная машина, которые обеспечивают приложения веб-браузера почти собственной производительностью и позволяют разработчикам создавать высокоскоростные веб-приложения на любом языке.
На протяжении уже двух десятилетий у нас есть лишь один язык программирования, который можно использовать в веб-браузере в исходном формате – это JavaScript. Медленная деградация сторонних бинарных программных расширений сбросила со счетов основных игроков веб-разработки, среди них такие языки, как Java и Flash ActionScript. А другие языки, такие как CoffeeScript, просто компилируются в JavaScript.
Но теперь у нас есть кое-что новое: WebAssembly, или сокращенно Wasm. WebAssembly – это небольшой быстрый двоичный формат, который обеспечивает веб-приложения почти собственной производительностью. К тому же, WebAssembly может компилировать любой язык, а JavaScript – всего один из них.
С учетом того, что все основные браузеры поддерживают WebAssembly, пришло время серьезно задуматься о том, чтобы начать писать клиентские веб-приложения, которые можно было бы скомпилировать как WebAssembly.
Важно отметить, что приложения WebAssembly не направлены на то, чтобы заменить приложения JavaScript – во всяком случае, не сейчас. Напротив, представьте, что WebAssembly – это компаньон JavaScript. В то время как JavaScript является гибким, динамически типизированным и доставляется в виде удобного для восприятия исходного кода, WebAssembly является высокоскоростным, строго типизированным и доставляется в компактном двоичном формате.
Разработчикам стоит рассмотреть WebAssembly в качестве отличного вариант для сценариев использования, которые требуют высокой производительности, например, игры, потоковая передача музыки, редактирование видео и CAD-приложения (системы автоматизированного проектирования). Многие веб-сервисы уже сделали этот шаг, например, Google Earth. Figma – приложение для совместных графических проектов, также приобщились к WebAssembly с целью сократить время загрузки и скорость выполнения, и это было еще даже тогда, когда WebAssembly был относительно новым.
Как работает WebAssembly
WebAssembly был разработан W3C, и, выражаясь словами его создателя, является «целевой платформой для компиляции». Разработчики не пишут код непосредственно на WebAssembly; они пишут его на предпочтительном для них языке, который затем компилируется в байт-код WebAssembly. Далее байт-код запускается на клиентской платформе – как правило, в веб-браузере – где он преобразовывается в собственный машинный код и выполняется на высокой скорости.
Код WebAssembly должен загружаться, анализироваться и выполняться быстрее, чем JavaScript. Когда веб-браузер использует WebAssembly, на загрузку и настройку модуля Wasm все также необходимы дополнительные ресурсы. Для более крупных проектов Wasm эти модули могут достигать размеров в несколько мегабайт, соответственно, задержки могут быть существенными.
WebAssembly также предоставляет изолированную модель выполнения, в основе которой лежат те же модели безопасности и в JavaScript. Приложения Wasm не могут получить доступ к чему бы то ни было за пределами изолированной программной среды, в том числе и к объектной модели веб-страницы, на которой они работают. Для любого взаимодействия с остальной частью машины необходимо использовать ABI (Application Binary Interface – двоичный интерфейс прикладных программ), такие как WebAssembly System Interface, сокращенно WASI, – системный интерфейс WebAssembly. WASI обеспечивает контролируемый доступ к файлам, сети, системным часам и другим системных службам, которые часто используются в программах.
ейчас самым распространенным вариантом использования WebAssembly является его запуск в веб-браузерах, но WebAssembly был задуман как нечто большее, чем просто веб-решение. Проект Wasmer запускает приложения WebAssembly на стороне сервера, практически аналогично тому, как среда выполнения Node.js запускает JavaScript вне браузера.
Сценарии использования WebAssembly
Самый примитивный вариант использования WebAssembly – это создание программного обеспечения для браузера. Компоненты, которые затем будут скомпилированы в WebAssembly, можно написать на любом из огромного числа языков; затем конечная полезная нагрузка WebAssembly доставляется клиенту через JavaScript.
WebAssembly был разработан с учетом ряда сценариев использования в браузере, которые требуют высокой производительности: игры, потоковая передача музыки, редактирование видео, CAD-приложения, шифрование и распознавание изображений, и здесь перечислены лишь некоторые из них.
В целом при определении индивидуального сценария использования WebAssembly будет полезно направить свое внимание на следующие три немаловажные составляющие:
- Высокопроизводительный код, который уже существует на каком-то языке. Например, если у вас есть высокоскоростная математическая функция, которая уже написана на С, и вы хотите добавить ее в веб-приложение, то вы можете развернуть ее как модуль WebAssembly. Части приложения, которые не так критичны с точки зрения производительности и ориентированные на пользователя, можно оставить в JavaScript.
- Высокопроизводительный код, который необходимо писать с нуля, и JavaScript для него не самый лучший вариант. Раньше, чтобы написать такой код, можно было воспользоваться asm.js. Вы по-прежнему можете сделать именно так, но WebAssembly все же считается лучшим долгосрочным решением.
- Перенос настольного приложения в веб-среду. Под эту категорию попадают многие технологические демонстрации для asm.js и WebAssenbly. WebAssembly может стать основой для приложений, которые являются более многообещающими, нежели обычный графический интерфейс, представленный через HTML.
Если у вас есть приложение JavaScript, которое не превышает предельную производительность, то лучше оставить его как есть на этом этапе разработки WebAssembly. Но, если вам необходимо ускорить это приложение, то WebAssembly – это то, что вам нужно.
Поддержка языка WebAssembly
WebAssembly не предназначен конкретно для написания кода. Судя по названию, это что-то, что похоже на язык ассемблера, то есть то, что может воспринимать машина, в отличие от высокоуровневого и удобного для восприятия языка программирования. WebAssembly находится ближе к промежуточной форме представления (IR – Intermediate Representation), созданной инфраструктурой компилятора языка низкоуровневой виртуальной машины, чем к C или Java.
В связи с этим, большая часть рабочих сценариев для WebAssembly включают в себя написание кода на высокоуровневом языке и его преобразование в WebAssembly. Для этого можно воспользоваться любым из трех основных способов:
- Прямая компиляция. Исходный код преобразуется в WebAssembly с помощью собственного набора инструментов компилятора языка. У Rust, C/C++, Kotlin/Native и D на данный момент есть свои собственные способы порождения Wasm из компиляторов, которые поддерживают эти языки.
- Сторонние инструменты. Язык не имеет встроенной поддержки Wasm в своем наборе инструментальных средств, но для того, чтобы преобразовать код в Wasm, можно воспользоваться сторонней программой. Такую поддержку имеют Java, Lua и семейство языков .Net.
- Интерпретатор на основе WebAssembly. Здесь не сам язык преобразуется в WebAssembly, а скорее интерпретатор языка, написанный на WebAssembly, запускает код, который был написан на этом языке. Это наиболее громоздкий подход, так как интерпретатор может состоять из нескольких мегабайт кода, но при этом с его помощью можно запустить уже существующий код, который был написан на каком-либо языке, по сути неизменным. У Python (например, через PyScript) и Ruby есть интерпретаторы, преобразованные в Wasm.
Особенности WebAssembly
WebAssembly все еще находится на начальных этапах своего развития. Набор инструментальных средств и реализация WebAssembly остаются ближе к внутреннему исследовательскому проекту, нежели к производственной технологии. Несмотря на это, разработчики WebAssembly имеют на примете ряд предложений для того, чтобы сделать WebAssembly более полезным:
Элементарные процедуры сборки мусора
WebAssembly напрямую не поддерживает языки, которые используют модели памяти с автоматическим сбором мусора. Такие языки, как Lua или Python, могут поддерживаться только посредством ограниченного набора функций или встраивания целой среды выполнения в качестве исполняемого файла WebAssembly. Впрочем, уже ведутся работы по организации поддержки моделей памяти с автоматической сборкой мусора без привязки к определенному языку или реализации.
Многопоточность
Встроенная поддержка многопоточности характерна для таких языков, как Rust и C++. Так как в WebAssembly отсутствует поддержка многопоточности, это означает, что мы не сможем написать целый ряд классов программного обеспечения, предназначенного для WebAssembly, на этих языках. В основе предложения добавить многопоточность в WebAssembly лежит прекрасный пример, а именно модель многопоточности C++.
Операции с памятью большого объема и архитектура SIMD
Операции с памятью большого объема и параллелизм SIMD (single instruction, multiple data – один поток команд-много потоков данных) являются обязательными для приложений, которые обрабатывают огромное количество данных и которым необходимо ускорить ЦП, чтобы избежать перегрузки, например, для программ машинного обучения или прикладных программ для научных исследований. Обсуждаются предложения по добавлению этих возможностей в WebAssembly с помощью новых операторов.
Высокоуровневые языковые конструкции
Большую часть других функций, рассматриваемых для WebAssembly, можно сопоставить с высокоуровневыми конструкциями на других языках.
- Исключения можно эмулировать в WebAssembly, но при этом их нельзя исходно реализовать их с помощью набора команд WebAssembly. Предлагаемый проект включает в себя простейшие исключения, которые совместимы с моделью исключений C++, которые, соответственно, могут использоваться другими языками, скомпилированными в WebAssembly.
- Ссылочные типы упрощают передачу объектов, которые используются в качестве ссылок на серверную среду. Это может упростить реализацию сборки мусора и целого ряда других высокоуровневых функций в WebAssembly.
- Завершающие вызовы - это шаблон проектирования, которые используется во многих языках.
- Функции, которые возвращают несколько значений, например, через кортежи в Python или C#.
- Операторы расширения знакового разряда – полезная низкоуровневая математическая операция. (Низкоуровневая виртуальная машина их также поддерживает.)
Инструменты отладки и профилирования
Одна из самых больших проблем транспилированного кода JavaScript заключалась в сложности отладки и профилирования из-за того, что нельзя было согласовать транспилированный код с исходным. У WebAssembly есть аналогичная проблема, и решается она точно также (поддержкой карты исходного кода).