WebAssembly находится в разработке уже более 8 лет. Технология прошла долгий путь развития и недавно разработчики из Bytecode Alliance выкатили версию 3.0.

О WebAssembly уже много материалов, но сегодня нам важна сама суть. У нас есть возможность, воспользовавшись любым из доступных языков программирования, написать модуль с необходимой нам логикой и запустить в исполняемой среде браузера. Разработчики обещают: модули будут быстрее и безопаснее, чем JavaScript, а также созданные ранее технологии, наподобие asm.js.

На связи Борис Мещеряков, фронтенд-разработчик в ПСБ и чаще всего мне приходится работать с javascript-фреймворками: React, Angular и прочими. Узнав о WebAssembly, я какое-то время наблюдал за его развитием. Мне стало интересно, может ли новая технология помочь мне уже сейчас? Какие ее возможности существуют на данный момент и какие реальны в будущем?

Разберёмся вместе?

Если обратиться к официальным ресурсам, картина более чем радужная. Прямо на главной странице проекта, мы видим следующие свойства:

  • Efficient and fast;

  • Safe;

  • Open and debuggable;

  • Part of open web platform.

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

Сначала казалось, что WebAssembly (Далее будет использоваться общепринятое сокращение— Wasm) — это «волшебная таблетка»: добавь в проект и получи скорость и безопасность. Но меня смущало, что при поиске модулей Wasm в популярных ресурсах через dev-tools браузера, мне не удавалось найти почти ничего. 

Беглый поиск по популярным ресурсам не находит никаких модулей Wasm
Беглый поиск по популярным ресурсам не находит никаких модулей Wasm

Каким-то многие обходятся без всяких волшебных Wasm-таблеток. Однако «где я и где они». В конце концов, у крупных компаний могут быть и серьезные основания:

  • Молодая технология -> дорого поддерживать;

  • Неясная безопасность;

  • Сложное легаси.

Примерно так я оправдывал для себя необходимость тратить время на неизвестную технологию. Кроме того, я точно знал, что есть те, кто уже Wasm активно использует:

Google в своей Google Earth: How we're bringing Google Earth to the web  |  web.dev

Figma ускоряет загрузку в 3 раза: Figma is powered by WebAssembly | Figma Blog

Чтобы понять, почему WebAssembly используется или не используется, нужно сперва понять, какие именно задачи он в состоянии решать. Что же нам предлагают Bytecode Alliance? Рассмотрим основные способы применения.

Классические приложения в браузере 

Этот вариант подойдет тем, у кого уже есть рабочее приложение, скомпилированное для работы в среде классических операционных систем, либо же для тех, кто целенаправленно стремится достичь одинакового user experience при работе в desktop- и web- версиях.

Например, этим путем пошел разработчик Google Earth, который использовал готовую C++‑кодовую базу и перенёс её в браузер.

И это далеко не единственная подобная миграция в web. Свои версии браузерных приложений представили такие мастодонты, как AutoCad, Photoshop и многие другие. Большую подборку приложений, использующих WebAssembly можно посмотреть здесь.

Речь, однако, не идет о стопроцентном портировании. Чаще всего у разработчиков есть большая кодовая база, которую по разным причинам не получится просто портировать на javascript (сложность/невозможность портирования, дороговизна параллельной поддержки нескольких версий и так далее). Поэтому из нее выделяют ключевые модули, которые затем компилируются в модули Wasm. Интерфейс для web-версии затем создается отдельно с помощью классических html/css/javascript. 

Интерфейс AutoCAD Web встречает нас родными div`ами
Интерфейс AutoCAD Web встречает нас родными div`ами

Можно отрисовывать интерфейс целиком в canvas — так делает библиотека egui для Rust. 

На первый взгляд у нас масса возможностей. WebAssembly подарил нам возможность запустить классические приложения в браузере. Почему же тогда мы не наблюдаем массовый исход пользователей в web и отказ от desktop? Почему мы не видим отказ от javascript-фреймворков, ведь теперь для отрисовки интерфейса в браузере мы больше не привязаны намертво к html/css/javascript? Здесь нам нужно поглубже вникнуть в то, как именно устроен браузерный WebAssembly.

WebAssembly наглядно

Ниже расположена схема, которая показывает, как именно выполняется код модуля Wasm:

На ней хорошо видно, что модуль Wasm способен работать напрямую только с ограниченным набором типов данных. Для доступа ко всем остальным возможностям браузера Wasm сперва обращается к javascript. Без javascript Wasm не сможет напрямую взаимодействовать с пользовательским интерфейсом. Для серьезных приложений нужны инструменты: сеть, файловая система, графика, HID. Также будет правильно разделить логику на несколько модулей для удобства.

 Стоит учитывать, каждый Wasm‑модуль работает в собственной области памяти. По умолчанию модули не могут напрямую обращаться к памяти друг друга, и для обмена данными часто используется JavaScript как посредник. Однако есть и более гибкие механизмы: например, можно настроить общую память через SharedArrayBuffer, что позволяет нескольким модулям работать с одним буфером и обмениваться данными без постоянных вызовов JS. Тем не менее, доступ к большинству возможностей браузера - DOM, сеть, графика - по‑прежнему идёт через JavaScript. Именно эта зависимость делает WebAssembly не “волшебной таблеткой”, а скорее, дополнением к экосистеме, которое раскрывает потенциал только в сочетании с JS.

Таким образом, мы видим двойственную природу WebAssembly в браузере. С одной стороны, он дает возможность запускать быстрый нативный код и даже делить память между модулями через SharedArrayBuffer. С другой - ключевые функции остаются за пределами его прямого доступа и требуют постоянного взаимодействия с JavaScript. Именно в этой точке ожидания сталкиваются с реальностью: архитектурные особенности превращаются в ограничения, которые заметны при создании сложных приложений. Рассмотрим основные проблемы подробнее.

Проблема скорости

WebAssembly обещает высокую производительность, но в реальности сталкивается с узким местом: каждое взаимодействие с браузером идёт через JavaScript. Сам код внутри Wasm‑модуля может работать довольно быстро, но вызовы к JS добавляют задержки, которые накапливаются и становятся заметны. В итоге выигрыш в скорости может нивелироваться постоянными переходами через «JS‑шлюз».

Проблема модульности

Изоляция памяти — фундаментальное свойство WebAssembly. Каждый модуль живёт в своём пространстве и не может напрямую обмениваться данными с другим. Для связи снова нужен JavaScript. Это делает модульность скорее ограничением, чем преимуществом: если приложение разбито на множество взаимосвязанных частей, производительность падает. А если собрать всё в один огромный модуль, он может весить десятки мегабайт — риск для веб‑приложений, где скорость загрузки критична.

Разработчики WebAssembly прекрасно понимают важность проблемы и активно работают над возможностью разделять Wasm на компоненты, способные взаимодействовать между собой напрямую (см. The WebAssembly Component Model). На данный момент поддержка в браузерах экспериментальная и включается вручную.

Google Earth загружает “скромные” > 6 Mb
Google Earth загружает «скромные» > 6 Mb

Проблема зависимости от JavaScript

WebAssembly не может напрямую работать с большинством браузерных API: сеть, файловая система, графика - всё это доступно только через JS. Даже простая задача «открыть файл» превращается в обходной манёвр с <input type="file">. Для графики ситуация ещё сложнее: WebGL и WebGPU отличаются от десктопных API, и библиотека, прекрасно работающая на ПК, может оказаться бесполезной в браузере. Разработчики уже ищут выход - проекты вроде wgpu и dawn стремятся создать единый кроссплатформенный слой, но пока это лишь шаги в нужном направлении.

Предварительные выводы

Теперь, когда мы знаем все основные подводные камни, можно вынести вердикт портированию desktop приложений в web. До полноценного портирования еще очень далеко.Для полноценного портирования WebAssembly нужны:

  • Более прямой доступ к браузерным API;

  • Модульность без потерь и сложных обходных путей;

  • Полноценный lazy loading;

  • Унифицированные библиотеки и экосистема.

Часть этих возможностей уже в разработке. Но пока разработка не завершена, с WebAssembly стоит связываться только когда есть возможность вынести основную логику в отдельный модуль, а для интерфейса параллельно разрабатывать две версии для web и для desktop. Это путь для тяжелых приложений с большой кодовой базой. 

Для тяжелых приложений есть и другой путь - тот, которым пошли разработчики Figma. Они изначально ставили цель создать продукт, который сможет конкурировать с desktop‑аналогами, при этом будет работать прямо в браузере. Когда Figma начинала, WebAssembly ещё не существовал, и они использовали его предшественника - asm.js. Позже, когда WebAssembly достаточно развился, команда просто перекомпилировала свой C++ движок в новый формат и получила примерно трехкратное ускорение времени загрузки. Это стало возможным благодаря тому, что WebAssembly - бинарный формат, который браузер может декодировать и компилировать значительно быстрее, чем огромные текстовые файлы asm.js, требующие полного парсинга как JavaScript.

Для более простых приложений есть смысл пойти обратным путем - сразу разрабатывать приложение сочетая популярные javascript-фреймворки и модули на Wasm, заточенные на решение конкретных высокопроизводительных задач. Будет ли выигрыш? Давайте разбираться.

Web-приложения с использованием Wasm-модулей

Современные js-фреймворки уже давно представляют собой серьезные инструменты. С их помощью можно создавать приложения, способные решать огромный спектр задач, а область работы давно вышла за пределы браузера - технологии веба уже давно и успешно живут как на десктопе, так и на мобильных устройствах. Основной язык программирования javascript уже давно разросся из простого скриптового языка до полноценного. Тем не менее, среди разработчиков нередко можно услышать мнение, что js - медленный язык. WebAssembly же напротив заявляется как высокопроизводительный. Значит, найти применение Wasm будет просто - выделяем из приложения самые узкие по производительности места, определяем причину, выносим логику в Wasm-модуль и получаем выигрыш. Ведь так?

Теоретически - да. Интерпретируемый js должен быть медленнее, особенно если речь идет о большом количестве операций с данными, либо о таких типах данных, которые js напрямую не поддерживает.

В то же время, хочется проверки именно на реальных задачах. Проблема в том, что реальные задачи клиентских web-приложений редко бывают сложнее традиционных crud-операций. Все основные вычисления по-традиции осуществляет backend-сервер. Но есть и задачи, в которых frontend также осуществляет большое количество сложных операций. Давайте выясним на примере нескольких таких операций, какой выигрыш в производительности даст Wasm.

Тестовый стенд

Для проверки будем использовать Docker. Соберем и поднимем два контейнера для теста. Первый контейнер - просто web-server на nginx, который отдает тестовый модуль. Второй - контейнер playwright (ПО для end2end тестирования, детальнее - здесь). Playwright запускается с параметрами:

--cpus="2.0" --cpuset-cpus="0,1" --memory="4g" --memory-swap="4g"

и встроенным браузером переходит по ссылке веб-сервера, затем выводит в консоль результаты тестирования. Таким образом получаем относительно стабильную тестовую среду - всегда одинаковая версия браузера и одно и тоже количество ресурсов.

Карты (Алгоритм Рамера - Дугласа - Пекера)

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

Шедевр из XVIII века. Источник
Шедевр из XVIII века. Источник

Детали работы алгоритма можно почитать тут. Мы же здесь попробуем сравнить, как быстро алгоритм обрабатывает разное количество координат в Wasm и чистом javascript.

Создадим JSON с наборами координат в 10-, 100-, и 1000- тысяч точек и попробуем упростить.

Разработчики часто любят шутить про медленный JavaScript. Что ж, это явно не тот случай - уже на 1 миллионе точек видим заметный отрыв в производительности.

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

Парсинг CSV

Таблицы. Куда же без таблиц. Таблицы повсюду. Возьмем csv-файл с условным перечнем людей. Всего четыре столбца: Порядковый номер, Имя/Фамилия, E-mail, Место работы. Попробуем парсить файлы 10-, 100- и 1000- тысяч значений и посмотреть, кто будет быстрее. 

На выходе мы должны получить вот такую табличку и результаты скорости парсинга:

Здесь дела у WebAssembly еще хуже, чем в предыдущем тесте. При парсинге файла с миллионом значений получаем, приблизительно, 10-кратный разрыв в пользу JavaScript.

Числа Фибоначчи

Классический пример рекурсии. Проверим, кто быстрее посчитает сумму ряда длиной в 10, 20 и 40 чисел:

Как заставить ваш браузер зависнуть в 2025 году ? Заставьте его считать числа Фибоначчи рекурсивно и вы увидите, что, как только ряд достигает 40+ чисел, вычисления становятся непосильными. И мы видим, что это первый тест в котором WebAssembly уверенно обходит чистый JavaScript в скорости вычислений.

Очень хорошо, только как теперь это преимущество использовать? В этом бенчмарке я использую рекурсивную версию:

function fib(n) { 

  if (n < 2) return n; 

  return fib(n - 1) + fib(n - 2); 

}

Она еще называется «Наивная рекурсивная версия». Наивная — потому что толку от нее в реальной жизни никакого. 

Совсем другое дело — итеративная версия. Она гораздо более производительна. JS-версия, например, позволяет считать ряд длиной в 1 млрд чисел и более. Такой объем вычислении уже гораздо ближе к потребностям реальной жизни. Посмотрим, кто справится быстрее.

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

Но как только мы перешли к чистым численным вычислениям, ситуация изменилась: WebAssembly стал работать быстрее примерно на 25%. Это объясняется тем, что Wasm использует примитивные числовые типы уровня железа и выполняет код предсказуемо, без JIT‑эвристик и лишних проверок. JavaScript тоже хорошо оптимизирован для чисел, но его универсальный тип Number и динамическая природа накладывают ограничения.

Теперь осталось самое главное — придумать, где именно в клиентских приложениях использовать алгоритмы на основе ряда чисел Фибоначчи (Спойлер — как и рекурсивную версию, нигде).

Криптография

Шифрование плотно вошло в современную жизнь. Еще каких-то лет 8-10 назад в интернет массово ходили без https, а энтузиасты спутникового интернета массово занимались «рыбалкой» — перехватом чужих данных. Хорошее было время. В современном же интернете достаточно поводов использовать шифрование как с клиентской, так и с серверной стороны. Возьмем популярный алгоритм шифрования SHA-384 и посмотрим, кто справится быстрее. Для JavaScript-версии будем использовать реализацию из популярной библиотеки js-sha. Оппонент на Rust/Wasm будет использовать пакет sha2. Зашифруем строку длиной 10-, 20- и 50- млн символов и посмотрим на результат:

Похоже, мы нашли нишу, в которой WebAssembly действительно сияет. Приблизительно двукратное преимущество. И я уверен, чем более продвинутый алгоритм мы возьмем, тем больше будет разрыв. Почему так происходит? Дело в том, что JavaScript хранит все числа в формате 64‑битного float, который удобен для обычной математики, но плохо подходит для криптографии. WebAssembly же работает с настоящими машинными типами — включая 64‑битные целые числа. Алгоритм SHA‑384 активно использует 64‑битные битовые операции, и Wasm выполняет их напрямую, тогда как JavaScript вынужден постоянно преобразовывать числа. Поэтому WebAssembly стабильно быстрее.

LLM

Как же в наше время обойтись без упоминания LLM. Здесь мы ступаем на территорию, где WebAssembly имеет неоспоримое преимущество перед JavaScript - принципиальную возможность запускать языковые модели. Фреймворк Candle позволяет запускать популярные модели прямо в браузере. В Llama 2 у меня получилось около 10 токенов в секунду:

Запуск LLM локально в браузере дает широкие возможности, если приложение требует наличия оффлайн-режима или предоставляет пользователям гарантии приватности. Но, конечно же, требует значительных ресурсов клиентского устройства.

Вывод

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

Однако существуют области, где динамическая природа JavaScript становится ограничением - криптография, обработка бинарных данных, линейная алгебра, работа с большими массивами чисел. В таких задачах WebAssembly показывает себя значительно лучше благодаря предсказуемой модели исполнения, нативным 32‑ и 64‑битным типам и отсутствию JIT‑деоптимизаций. Поэтому оптимальная стратегия - не противопоставлять JS и Wasm, а использовать каждый инструмент там, где он раскрывает свои сильные стороны.

Лирическое отступление: Blazor WebAssembly и мечта о «браузере без JavaScript»

Когда речь заходит о WebAssembly, неизбежно всплывает Blazor WebAssembly — проект, который часто подают как «альтернативу JavaScript» и даже как попытку построить веб‑приложения без единой строчки JS. На самом деле всё куда интереснее.

Blazor существует в двух формах. Первая — Blazor Server — классический веб‑фреймворк, где вся логика работает на сервере, а браузер получает только HTML и CSS. Вторая — Blazor WebAssembly — куда более амбициозная: в браузер загружается мини‑рантайм .NET, скомпилированный в WebAssembly, и всё приложение работает прямо внутри Wasm. JavaScript остаётся лишь тонким слоем клея между .NET‑кодом и браузерными API.

Но важно понимать: Blazor WebAssembly — это не попытка заменить JavaScript как платформу. Это попытка перенести в браузер экосистему .NET. Он не универсален, не нейтрален и не «открыт» в широком смысле — он жестко привязан к .NET и развивается в рамках одной экосистемы. Это не новый язык веба, а способ дать .NET‑разработчикам возможность писать клиентский код на знакомом стеке.

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

Заключение

Волшебной таблетки нет. Есть долгий и непростой переходный период, в котором веб‑приложения становятся всё сложнее, а объем вычислений растет быстрее, чем возможности классического стека. И действительно создаётся ощущение, что мы приблизились к естественным пределам той производительности, которую можно получить от JavaScript в задачах тяжёлой арифметики. Возникает логичный вопрос: почему бы просто не добавить в JS всё то, что даёт WebAssembly?

Ответ — в истории и природе самого языка. JavaScript создавался как простой инструмент для небольших интерактивных скриптов, и его динамическая модель была осознанным выбором: типы, структуры данных и даже функции могли меняться на лету. Эта гибкость идеально подходила для интерфейсов, событий и логики приложения. За десятилетия браузеры довели эту модель до впечатляющей эффективности, и сегодня JS остается лучшим инструментом для всего, что связано с взаимодействием с веб‑платформой.

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

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

Комментарии (2)


  1. AleGen
    28.04.2026 07:08

    У Вас в заголовке ошибка.


    1. LilouX
      28.04.2026 07:08

      спасибо, пофиксили. Запасную букву убрали в запасник букв)