Проблема, которую решает Wasm

Разбираемся, какую конкретную боль закрывает WebAssembly.

Проблема Wasm — это тяжёлые вычисления в вебе: игры, видео, CAD, эмуляторы, которые JavaScript тянет с трудом или непредсказуемо.

В чём боль JavaScript

JavaScript — прекрасный язык для интерфейсов: кнопки, формы, запросы к серверу, анимации. Но он динамически типизирован. Это значит, что движок не знает заранее, что лежит в переменной: число, строка или объект. Когда вы пишете a + b, движку приходится в момент выполнения проверять типы и решать, что делать. Современные JIT-компиляторы умеют угадывать типы и оптимизировать горячий код, но эти оптимизации хрупкие: стоит передать в функцию неожиданный тип — и движок «деоптимизирует» её, откатываясь к медленному пути.

Для веб-страницы это незаметно. Но для задач, где миллионы операций в секунду идут в цикле, непредсказуемость убивает производительность. Представьте редактор видео, который должен обработать каждый пиксель каждого кадра, или 3D-игру с физикой и тысячами объектов.

Какие задачи требовали решения

ЗадачаПочему тяжела для JS
3D-игры (Unity, Unreal)Физика, рендеринг, миллионы операций за кадр
ВидеокодекиДекодирование потока в реальном времени, побитовые операции
CAD и графика (Figma, Photoshop)Геометрия, обработка больших изображений
Эмуляторы (DOSBox, ретро-консоли)Точная и быстрая эмуляция чужого процессора
Криптография, сжатиеИнтенсивная арифметика, побитовые сдвиги

Маленький эксперимент на JS

Чтобы почувствовать, о каком объёме работы речь, посчитаем сумму квадратов в большом цикле. Для современного движка это быстро, но представьте, что таких циклов — сотни на каждый кадр игры.

function sumSquares(n) {
  let total = 0;
  for (let i = 1; i <= n; i++) {
    total += i * i;
  }
  return total;
}
console.log(sumSquares(100000));

Вывод:

333338333350000

JS справится с этим мгновенно. Но в реальной игре подобные циклы переплетены с обработкой объектов, чтением памяти, ветвлениями — и тут предсказуемая, заранее оптимизированная Wasm-версия выигрывает стабильно.

Как работает под капотом решение

Wasm убирает неопределённость. У каждой инструкции жёстко заданы типы операндов: эта сложит два i32, эта умножит два f64. Движку не нужно гадать — он сразу генерирует оптимальный машинный код. Нет деоптимизаций, нет сборщика мусора, который в неожиданный момент остановит игру для очистки памяти. Производительность предсказуема, а это для игр и реального времени важнее, чем пиковая скорость.

Частые ошибки в понимании

  • «JS просто медленный» — нет, JS быстрый. Проблема в непредсказуемости на тяжёлых нагрузках, а не в абсолютной скорости.
  • «Wasm нужен для любого сайта» — нет. Для форм и кнопок JS идеален. Wasm оправдан там, где есть вычислительное ядро.
  • «Достаточно переписать всё на Wasm» — нет. Интерфейс и работу с DOM удобнее оставить на JS.

Итоги

  • JavaScript непредсказуем на тяжёлых вычислениях из-за динамической типизации.
  • Игры, видео, CAD, эмуляторы требовали стабильно быстрого кода в браузере.
  • Wasm даёт жёсткие типы, отсутствие GC по умолчанию и предсказуемую скорость.
Проверьте себя
1. Почему JavaScript бывает непредсказуем на тяжёлых задачах?
AОн всегда работает в одном потоке
BИз-за динамической типизации движок может деоптимизировать горячий код
CОн не умеет работать с числами
DОн запрещает циклы
2. Какое преимущество Wasm важнее всего для игр реального времени?
AМаксимальная пиковая скорость любой ценой
BПредсказуемая, стабильная производительность без внезапных пауз GC
CКрасивый синтаксис
DАвтоматический доступ к DOM