Сегодня мы поговорим об одной истории. Рассказ о небольшой компании по разработке программного обеспечения.

История

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

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

… Перенесемся на 3 месяца, все работало как швейцарские часы.

После первого успеха на мобильных платформах компания C-Suite решила также использовать Web, что-то вроде веб-приложения «конвертер изображений», созданного с использованием таких интерфейсных технологий, как HTML, CSS и javascript.
… Не говори больше, разработчики интегрировали простой веб-сайт с API преобразования изображений в течение 24 часов, и все работало без тени сомнения идеально.

… До того момента, когда клиенты масштабировались настолько сильно, что сервер не мог выполнять достаточно вычислений для удовлетворения потребностей каждого клиента, поэтому временно приложение масштабировалось по горизонтали.

Тем временем компания искала решение возникшей проблемы.
Они решили перенести логику преобразования во внешний интерфейс. Это означает, что приложения для Android и IOS будут преобразовывать изображения внутри приложения, не отправляя их в веб-API.

Это было потрясающе, пока они не выяснили, что забыли веб-версию, где им пришлось перенести всю эту библиотеку C ++ на JavaScript. Да, JavaScript.
Что это значит? - Это означает написание алгоритма преобразования с нуля на JavaScript, повторное написание модульных тестов, написание дополнительных модульных тестов из-за странных типов данных JavaScript, тестирование его во всех браузерах.

Что ж, давайте будем честными. Хотя бы раз в жизни вы представляли, что запускаете какой-нибудь язык программирования, отличный от JavaScirpt, в веб-браузере.
Угадайте, они надеялись, что такая технология существует, потому что они должны были как можно скорее выпустить новый веб-релиз .

«Невероятное», ставшее реальностью

Итак, как все началось…?
Все началось в один солнечный день, когда трое друзей по имени Microsoft, Google и Mozilla решили выпить кофе и обсудить тему «браузеры».

Они говорили об общих проблемах, с которыми сталкивается каждый разработчик javascript, таких как обратная совместимость при использовании современных версий ECMAScript и кроссбраузерные проблемы, потому что мы разрабатываем один код JavaScript, но он интерпретируется и выполняется по-разному для каждого механизма JavaScript, что означает, что у вас могут быть некоторые ошибки. вон там.

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

наоборот.

Стандарт

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

Итак, о чем новый стандарт?
Он о том, как браузер будет рассматривать наш код. Представьте, что у вас есть статический веб-сайт HTML5, и вам нужно загрузить свой JavaScript, чтобы добавить какое-то взаимодействие.
Естественно, что большинство разработчиков делают, это помещают тег «script» с атрибутом «href», который указывает на ваш JavaScript. где-нибудь в Интернете.

Все в порядке, но как мы собираемся загрузить наш собственный код в браузер?
Дело в том, что мы вообще не будем загружать собственный код в браузер, вместо этого мы загрузим некоторые двоичные файлы, содержащие расширение файла «.wasm» (WebAssembly).

Двоичные файлы

Мы собираемся загружать двоичные файлы вместо текстовых файлов. Теперь вы, вероятно, спрашиваете себя, каков двоичный контент в этом файле и как мы собираемся его сгенерировать. Ответ прост. Мы будем использовать магию.
То же волшебство, которое мы используем для преобразования нашего исходного кода в двоичные файлы, называемые «.dll» и «.exe», и это волшебство называется компилятором.

Если вы попытаетесь открыть сгенерированный файл «.wasm», вы не увидите ничего, кроме кучи символов, нечитаемых человеком. Это потому, что файлы «.wasm» - это предварительно скомпилированные файлы, они не содержат исходного кода.

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

Давайте посмотрим, как работает загрузка javascript в простые шаги.
Код JavaScript загружается, затем он несколько раз анализируется / токенизируется / интерпретируется и оптимизируется, и, наконец, некоторый байт-код загружается в виртуальную машину.
С другой стороны. Кроме того, WebAssembly уже оптимизирован во время компиляции, и браузер получает его как предварительно скомпилированный. Зная это, мы теперь на несколько шагов впереди по сравнению с JavaScript.

Если вы разработчик с опытом работы в dotnet, вы, вероятно, знаете, что означает Intermediate Language (IL). Это позволяет нескольким технологиям работать в одной среде выполнения и взаимодействовать друг с другом. Например, может быть настольное приложение, в котором некоторые плагины разработаны на VisualBasic или C ++. Сначала компилятор превращает исходный код в промежуточный язык, а затем промежуточный язык выполняется средой выполнения. Другими словами, это цель компиляции.

Зная это, теперь мы можем рассматривать WebAssembly как цель компиляции. Это означает, что мы можем скомпилировать наш собственный код в wasm и позволить JavaScript взаимодействовать с ним.

Более того, WebAssembly - это не что иное, как набор инструкций, упакованных в модуль. Существует также текстовое представление wasm-файла, удобочитаемое, и оно называется WebAssembly Text (. Wat). .Wat состоит из AST (абстрактного синтаксического дерева) и так называемых S-выражений. Более подробную информацию об AST вы можете найти по этой ссылке.

Представление

Одна из лучших вещей, которые предоставляет технология WebAssembly, - это производительность. И предпочтительнее использовать WebAssembly, когда у нас есть тяжелые вычислительные ресурсы ЦП, такие как игры, редактирование видео, обработка изображений и т. Д.

Но подождите секунду! - Если wasm более производительно, чем JavaScript, почему мы не компилируем JavaScript в wasm? WebAssembly как технология работает быстрее, когда мы компилируем языки программирования среднего уровня, такие как C / C ++ / Rust.
Почему? Потому что им не нужна специальная среда выполнения. В отличие от C / C ++, у языков высокого уровня, таких как C # и Java, есть особые требования, то есть вам нужно будет отправить всю их среду выполнения, чтобы иметь возможность запускать их.
Так что ответ будет большим НЕТ, мы не можем скомпилировать JavaScript в wasm без доставки всей среды выполнения.

Оптимизация

Мы упомянули некоторую оптимизацию во время компиляции. Нет нормального компилятора, который не оптимизировал бы простую операцию сложения между 2 или более константами во время компиляции.

var result = 1 + 2;
//will be optimized into
var result = 3;

Превращение C ++ в JavaScript.

Между тем, пока корпоративные компании изобретали WebAssembly, некоторые ребята уже придумали «своего рода» решение. Они создали Emscripten, компилятор LLVM в JavaScript с открытым исходным кодом.
Его основная цель заключалась в компиляции кода C и C ++ в JavaScript, кроме того, он мог скомпилировать любой другой код, который можно преобразовать в битовый код LLVM в JavaScript. < br /> Emscripten выводит быстрый и оптимизированный код. Его формат по умолчанию - «asm.js», высоко оптимизируемое подмножество JavaScript, которое во многих случаях может выполняться со скоростью, близкой к собственной.

Позже, когда были выпущены чертежи технологии WebAssembly, был создан Binaryen, который служил компилятором, превращающим asm.js в wasm.

Вернуться к истории

Все, что нам было нужно, это способ использовать наш код C ++ в браузере. Теперь с WebAssembly это более чем возможно. Мы можем легко использовать Emscripten и Binaryen для компиляции наших библиотек C ++ с WebAssembly в качестве цели компиляции.
Угадайте, что! Именно это и произошло с множеством крупных кодовых баз, таких как Unity3D Game Engine, Unreal Engine 4 и многие другие.

Пропавший материал

На данный момент WebAssembly как технология достаточно развита для ее использования, но как насчет использования некоторых API-интерфейсов браузера? Как «консоль», «окно», как мы собираемся получить доступ к «элементам DOM»?
На данный момент нет конкретных реализаций по этим темам, ни для сборки мусора, ни для многопоточности (лучший кандидат на будущее) .

Отсутствие сборки мусора означает, что мы сами должны об этом заботиться.
В случаях, когда мы отправляем нашу среду выполнения, например с C # мы также поставляем моно среду выполнения, а среда выполнения уже реализовала сборку мусора. То же самое и с многопоточностью. Если среда выполнения реализовала это, он доступен.

JavaScript Interops

Наличие API-интерфейсов браузера, реализованных фреймворком, - это здорово, но как они на самом деле реализованы или что, если некоторые из них отсутствуют, как мы можем добавить в WebAssembly функциональность, которая еще не доступна?

Что ж, помните, когда мы упоминали ранее «клей-код»? Это код, который получает наш wasm-файл с сервера и загружает его в браузер. «Склеивающий код» также может делать некоторые дополнительные вещи, например, добавлять в модуль некоторую информацию для реализации методов.

Поначалу это может сбивать с толку, но мы попробуем разобрать это на примере.
Предположим, что у нас есть кнопка на нашем веб-сайте, в которой есть простой счетчик посещений.
counter будет вести себя следующим образом:
Когда мы нажимаем кнопку, мы хотим увеличить значение в нашем коде. Затем абзац будет заполнен новым значением.

Реализация будет простой. Привязка события «OnClick» к кнопке, поэтому при нажатии кнопки будет вызываться метод из модуля WebAssembly с именем «incrementCounter». Мы сохраним наше «counterValue» в глобальной переменной в коде C ++.
Реализация метода «incrementCounter» увеличит глобальную переменную «counterValue». Затем нам нужно обновить абзац новым увеличенным значением.
Поскольку у нас нет сборки мусора, мы не можем отслеживать ссылки на элементы DOM.
Нам нужно найти другое обходное решение, вызвав метод, помеченный как «extern», что означает, что реализация этого метода будет предоставляться извне (это зависит от каждого языка программирования).
При загрузке Модуль WebAssembly с использованием «связующего кода», мы можем предоставить модулям реализации для недостающих методов (тех, которые помечены как «extern»). В нашем случае мы можем перейти к модулю WebAssembly, реализации, которая обновляет значение абзаца.

Исходный код примера счетчика посещений предоставлен здесь.

Надеюсь, статья вам понравилась.
Если у вас есть комментарии, поделитесь ими :)