Introducao ao WebAssembly - Formato Binario de Alta Velocidade no Navegador

Avancado | 2025.12.02

O que e WebAssembly

WebAssembly (WASM) e um formato de instrucao binaria executavel no navegador. Pode ser compilado a partir de linguagens como C/C++, Rust e Go, permitindo executar codigo nativo com desempenho proximo ao JavaScript.

flowchart LR
    subgraph Source["Codigo Fonte"]
        Rust["Rust"]
        Cpp["C/C++"]
        Go["Go"]
    end

    subgraph Compile["Compilacao"]
        LLVM["LLVM"]
        WASM[".wasm<br/>Binario"]
    end

    subgraph Runtime["Ambiente de Execucao"]
        Browser["Browser<br/>Runtime"]
        JS["Chamado de<br/>JavaScript"]
    end

    Source --> LLVM --> WASM --> Browser
    WASM --> JS

Caracteristicas:

  • Velocidade de execucao proxima ao nativo
  • Independente de linguagem (suporte multi-linguagem)
  • Execucao segura em sandbox
  • Interoperabilidade com JavaScript
  • Suporte a compilacao em streaming

Comparacao de Desempenho

ProcessamentoJavaScriptWASMNativo
Multiplicacao de matrizes (1000x1000)2.500ms850ms700ms
Processamento de imagem (1920x1080)180ms72ms-
Criptografia (AES-256)320ms125ms-

*A diferenca pode diminuir devido a otimizacao JIT do engine JS

Rust + WebAssembly

Configuracao

# Instalar wasm-pack
cargo install wasm-pack

# Criar projeto
cargo new --lib wasm-example
cd wasm-example
# Cargo.toml
[package]
name = "wasm-example"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["console"] }

[profile.release]
opt-level = "z"     # Otimizacao de tamanho
lto = true          # Otimizacao em tempo de link

Implementacao em Rust

// src/lib.rs
use wasm_bindgen::prelude::*;

// Funcao chamavel do JavaScript
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// Funcao que lida com strings
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

// Exportacao de struct
#[wasm_bindgen]
pub struct Calculator {
    value: f64,
}

#[wasm_bindgen]
impl Calculator {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Calculator {
        Calculator { value: 0.0 }
    }

    pub fn add(&mut self, x: f64) {
        self.value += x;
    }

    pub fn subtract(&mut self, x: f64) {
        self.value -= x;
    }

    pub fn multiply(&mut self, x: f64) {
        self.value *= x;
    }

    pub fn divide(&mut self, x: f64) -> Result<(), JsValue> {
        if x == 0.0 {
            return Err(JsValue::from_str("Division by zero"));
        }
        self.value /= x;
        Ok(())
    }

    pub fn get_value(&self) -> f64 {
        self.value
    }

    pub fn reset(&mut self) {
        self.value = 0.0;
    }
}

// Processamento de arrays
#[wasm_bindgen]
pub fn sum_array(arr: &[i32]) -> i32 {
    arr.iter().sum()
}

// Usando console do JS
#[wasm_bindgen]
pub fn log_to_console(message: &str) {
    web_sys::console::log_1(&message.into());
}

// Exemplo de processamento de imagem de alta velocidade
#[wasm_bindgen]
pub fn apply_grayscale(data: &mut [u8]) {
    for chunk in data.chunks_exact_mut(4) {
        let r = chunk[0] as f32;
        let g = chunk[1] as f32;
        let b = chunk[2] as f32;
        // Coeficientes ITU-R BT.601
        let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;
        chunk[0] = gray;
        chunk[1] = gray;
        chunk[2] = gray;
        // chunk[3] (alpha) permanece inalterado
    }
}

// Sequencia de Fibonacci (para benchmark)
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u64 {
    if n <= 1 {
        return n as u64;
    }
    let mut a: u64 = 0;
    let mut b: u64 = 1;
    for _ in 2..=n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    b
}

Build e Uso

# Build
wasm-pack build --target web --release
// Uso a partir de JavaScript/TypeScript
import init, {
  add,
  greet,
  Calculator,
  sum_array,
  apply_grayscale,
  fibonacci
} from './pkg/wasm_example.js';

async function main() {
  // Inicializacao do modulo WASM
  await init();

  // Chamada basica de funcao
  console.log(add(2, 3)); // 5
  console.log(greet('World')); // "Hello, World!"

  // Uso de classe
  const calc = new Calculator();
  calc.add(10);
  calc.multiply(2);
  console.log(calc.get_value()); // 20

  // Processamento de array
  const arr = new Int32Array([1, 2, 3, 4, 5]);
  console.log(sum_array(arr)); // 15

  // Processamento de imagem
  const canvas = document.getElementById('canvas') as HTMLCanvasElement;
  const ctx = canvas.getContext('2d')!;
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  apply_grayscale(imageData.data);
  ctx.putImageData(imageData, 0, 0);

  // Medicao de desempenho
  console.time('WASM Fibonacci');
  fibonacci(40);
  console.timeEnd('WASM Fibonacci');
}

main();

C/C++ + Emscripten

Configuracao

# Instalar Emscripten
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Implementacao C++

// src/main.cpp
#include <emscripten/bind.h>
#include <vector>
#include <string>
#include <cmath>

// Funcao basica
int add(int a, int b) {
    return a + b;
}

std::string greet(const std::string& name) {
    return "Hello, " + name + "!";
}

// Exportacao de classe
class Vector2D {
public:
    float x, y;

    Vector2D() : x(0), y(0) {}
    Vector2D(float x, float y) : x(x), y(y) {}

    float length() const {
        return std::sqrt(x * x + y * y);
    }

    Vector2D normalize() const {
        float len = length();
        if (len == 0) return Vector2D();
        return Vector2D(x / len, y / len);
    }

    Vector2D add(const Vector2D& other) const {
        return Vector2D(x + other.x, y + other.y);
    }

    float dot(const Vector2D& other) const {
        return x * other.x + y * other.y;
    }
};

// Operacao de matriz de alta velocidade
std::vector<float> matrixMultiply(
    const std::vector<float>& a,
    const std::vector<float>& b,
    int n
) {
    std::vector<float> result(n * n, 0.0f);

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            float sum = 0.0f;
            for (int k = 0; k < n; ++k) {
                sum += a[i * n + k] * b[k * n + j];
            }
            result[i * n + j] = sum;
        }
    }

    return result;
}

// Binding com Embind
EMSCRIPTEN_BINDINGS(module) {
    emscripten::function("add", &add);
    emscripten::function("greet", &greet);
    emscripten::function("matrixMultiply", &matrixMultiply);

    emscripten::class_<Vector2D>("Vector2D")
        .constructor<>()
        .constructor<float, float>()
        .property("x", &Vector2D::x)
        .property("y", &Vector2D::y)
        .function("length", &Vector2D::length)
        .function("normalize", &Vector2D::normalize)
        .function("add", &Vector2D::add)
        .function("dot", &Vector2D::dot);

    emscripten::register_vector<float>("FloatVector");
}

Build

emcc src/main.cpp \
  -o build/module.js \
  -s WASM=1 \
  -s MODULARIZE=1 \
  -s EXPORT_NAME="createModule" \
  -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \
  --bind \
  -O3

Integracao com JavaScript

// Metodos de carregamento do modulo WASM

// 1. Carregamento basico
const wasmModule = await WebAssembly.instantiateStreaming(
  fetch('/module.wasm'),
  importObject
);

// 2. Usando wasm-bindgen
import init, { add } from './pkg/module.js';
await init();
console.log(add(1, 2));

// 3. Memoria compartilhada
const memory = new WebAssembly.Memory({ initial: 256, maximum: 512 });

const importObject = {
  env: {
    memory,
    // Chamar funcao JavaScript do WASM
    jsLog: (ptr: number, len: number) => {
      const bytes = new Uint8Array(memory.buffer, ptr, len);
      const str = new TextDecoder().decode(bytes);
      console.log(str);
    },
  },
};

// 4. Passando dados grandes
function passLargeArray(wasmInstance: WebAssembly.Instance, data: Float32Array) {
  const { memory, alloc, dealloc, process } = wasmInstance.exports as any;

  // Copiar dados para memoria WASM
  const ptr = alloc(data.byteLength);
  const wasmArray = new Float32Array(memory.buffer, ptr, data.length);
  wasmArray.set(data);

  // Executar processamento
  process(ptr, data.length);

  // Obter resultado
  const result = new Float32Array(memory.buffer, ptr, data.length).slice();

  // Liberar memoria
  dealloc(ptr, data.byteLength);

  return result;
}

Casos de Uso Praticos

flowchart TB
    subgraph UseCases["Casos de Uso do WebAssembly"]
        subgraph Media["1. Processamento de Imagem/Video"]
            M1["Figma (ferramenta de design)"]
            M2["Squoosh (compressao de imagem)"]
            M3["FFmpeg.wasm (conversao de video)"]
        end

        subgraph Games["2. Jogos/3D"]
            G1["Unity WebGL"]
            G2["Unreal Engine"]
            G3["Godot Engine"]
        end

        subgraph Tools["3. Ferramentas de Desenvolvimento"]
            T1["VS Code (Monaco Editor)"]
            T2["Pyodide (Python no navegador)"]
            T3["SQLite WASM"]
        end

        subgraph Security["4. Criptografia/Seguranca"]
            S1["1Password (gerenciador de senhas)"]
            S2["Signal (chat criptografado)"]
            S3["Calculo de hash"]
        end
    end

Otimizacao de Tamanho

# Para Rust
# Otimizacao com wasm-opt
wasm-opt -Oz input.wasm -o output.wasm

# Compressao
gzip -9 output.wasm
# Compressao Brotli (mais eficiente)
brotli -9 output.wasm
# Configuracao de otimizacao no Cargo.toml
[profile.release]
opt-level = "z"      # Otimizacao prioridade tamanho
lto = true           # Otimizacao em tempo de link
codegen-units = 1    # Unidade de geracao de codigo para 1
panic = "abort"      # Abortar em caso de panic
strip = true         # Remover informacao de simbolos

WASI (WebAssembly System Interface)

// Codigo Rust compativel com WASI
use std::fs;
use std::io::{self, Write};

fn main() {
    // Leitura e escrita de arquivos
    let content = fs::read_to_string("/input.txt").unwrap();
    fs::write("/output.txt", content.to_uppercase()).unwrap();

    // Saida padrao
    println!("Hello from WASI!");

    // Variaveis de ambiente
    for (key, value) in std::env::vars() {
        println!("{}: {}", key, value);
    }
}
# Build com target WASI
rustup target add wasm32-wasi
cargo build --target wasm32-wasi --release

# Executar com wasmtime
wasmtime target/wasm32-wasi/release/app.wasm

Suporte de Navegadores

NavegadorStatus de Suporte
Chrome57+ (desde 2017)
Firefox52+ (desde 2017)
Safari11+ (desde 2017)
Edge16+ (desde 2017)
Node.js8+ (desde 2017)
← Voltar para a lista