Работа с WebAssembly и TypeScript: от А до Я — полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в WebAssembly и TypeScript

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

WebAssembly позволяет запускать код, написанный на C, C++, Rust и других языках, в браузере. TypeScript, в свою очередь, добавляет строгую типизацию и улучшает читаемость кода. Вместе они открывают новые возможности для обработки видео, 3D-графики, криптографии и других ресурсоёмких задач.

Основные концепции WebAssembly

Что такое WebAssembly?

WebAssembly — это виртуальная машина с бинарным форматом инструкций. Код компилируется в файлы .wasm, которые затем загружаются и выполняются в браузере. Основные преимущества:

  • Производительность: выполнение близко к нативной скорости
  • Безопасность: изолированное выполнение в песочнице
  • Переносимость: работает во всех современных браузерах
  • Интеграция: легко вызывается из JavaScript/TypeScript

Форматы WebAssembly

Существует два основных формата:

  • Двоичный (.wasm): компактный бинарный формат для выполнения
  • Текстовый (.wat): человекочитаемое представление Wasm

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

Настройка окружения для работы с WebAssembly и TypeScript

Необходимые инструменты

Для начала работы потребуется:

  • Node.js (версия 16+)
  • TypeScript компилятор
  • AssemblyScript (если пишем на TypeScript-подобном синтаксисе)
  • Браузер с поддержкой WebAssembly

Установка AssemblyScript

AssemblyScript — это язык, который компилирует TypeScript-подобный код в WebAssembly. Установка:

npm init -y
npm install --save-dev assemblyscript
npx asinit .

После этого создаётся структура проекта с файлами assembly/index.ts и конфигурацией.

Написание первого модуля на AssemblyScript

Создадим простую функцию сложения в файле assembly/index.ts:

export function add(a: i32, b: i32): i32 {
  return a + b;
}

Обратите внимание на тип i32 — это целое 32-битное число, специфичное для AssemblyScript.

Компиляция в WebAssembly

Выполните команду для компиляции:

npx asc assembly/index.ts -o build/optimized.wasm --optimize

Флаг --optimize включает оптимизацию размера и производительности. На выходе получаем файл build/optimized.wasm.

Интеграция WebAssembly с TypeScript

Загрузка Wasm модуля

Создадим TypeScript файл для загрузки и вызова Wasm функций:

// wasm-loader.ts
export async function loadWasmModule(): Promise<WebAssembly.Module> {
  const response = await fetch('build/optimized.wasm');
  const bytes = await response.arrayBuffer();
  return WebAssembly.compile(bytes);
}

export async function instantiateModule(): Promise<WebAssembly.Instance> {
  const module = await loadWasmModule();
  const instance = await WebAssembly.instantiate(module);
  return instance;
}

Вызов Wasm функций из TypeScript

Теперь создадим основной файл приложения:

// main.ts
import { instantiateModule } from './wasm-loader';

async function main() {
  try {
    const instance = await instantiateModule();
    const { add } = instance.exports as { add: (a: number, b: number) => number };
    
    const result = add(5, 7);
    console.log(`Результат сложения: ${result}`); // 12
  } catch (error) {
    console.error('Ошибка загрузки Wasm:', error);
  }
}

main();

Работа с памятью и строками

WebAssembly работает с линейной памятью. Для передачи строк используйте буферы:

// assembly/string-utils.ts
export function greet(namePtr: usize, nameLen: i32): usize {
  // Чтение строки из памяти
  const name = String.UTF8.decode(
    memory.buffer.slice(namePtr, namePtr + nameLen)
  );
  
  const greeting = `Hello, ${name}!`;
  // Кодирование и возврат указателя
  return String.UTF8.encode(greeting);
}

В TypeScript для работы с памятью используйте TextEncoder и TextDecoder:

// string-handler.ts
const encoder = new TextEncoder();
const decoder = new TextDecoder();

function callGreet(name: string): string {
  const encoded = encoder.encode(name);
  const ptr = instance.exports.allocate(encoded.length);
  
  // Копируем данные в Wasm память
  const memory = instance.exports.memory as WebAssembly.Memory;
  const buffer = new Uint8Array(memory.buffer);
  buffer.set(encoded, ptr);
  
  const resultPtr = instance.exports.greet(ptr, encoded.length);
  // Читаем результат
  const resultLen = new Uint32Array(memory.buffer, resultPtr - 4, 1)[0];
  const resultBytes = new Uint8Array(memory.buffer, resultPtr, resultLen);
  
  return decoder.decode(resultBytes);
}

Оптимизация производительности

Советы по оптимизации

  • Минимизируйте передачу данных: передавайте большие объёмы данных через общую память
  • Используйте WebAssembly.instantiateStreaming: для потоковой загрузки
  • Кэшируйте скомпилированные модули: используйте IndexedDB
  • Избегайте частых вызовов: группируйте операции в одну функцию

Пример с потоковой загрузкой

// streaming-loader.ts
async function loadStreaming(): Promise<WebAssembly.Instance> {
  const response = await fetch('build/optimized.wasm');
  const result = await WebAssembly.                

Блоги

Рекомендаций по книгам