JS vs. WebAssembly

An Interactive Report on Performance

The Problem: Slow JavaScript

This report explores a common developer challenge: computationally intensive tasks, like image processing, can be slow in JavaScript, leading to a poor user experience. When applying a filter to a high-resolution image, the browser's main thread can lock up, causing the UI to freeze.

The standard JavaScript approach involves iterating through every pixel of an image on a canvas, which is effective but not always performant enough for a smooth interface.

Interactive Demo

Experience the difference yourself. Upload an image (or use the default), then apply a grayscale filter using both pure JavaScript and a simulated WebAssembly module. Watch the timers to see the performance gap.

2. Apply grayscale filter

Results

JavaScript Time

- ms

WebAssembly Time

- ms

The Solution: A 3-Step Playbook

The performance gain was achieved by surgically replacing the slow JavaScript function with a Rust-based WebAssembly module. This process is more accessible than it sounds. Here is the code from the report, broken down by step.

The core image filtering logic is translated into a Rust function. The structure is very similar to the JavaScript equivalent, but it benefits from Rust's performance and type safety.

// The fast Rust version
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn apply_grayscale_wasm(data: &mut [u8]) {
    for i in (0..data.len()).step_by(4) {
        let avg = ((data[i] as u32 + 
                    data[i + 1] as u32 + 
                    data[i + 2] as u32) / 3) as u8;
        data[i]     = avg; // red
        data[i + 1] = avg; // green
        data[i + 2] = avg; // blue
    }
}

A command-line tool, `wasm-pack`, compiles the Rust code into an optimized WebAssembly binary and generates the necessary JavaScript "glue" code to make it usable on the web.

# This one command does it all
wasm-pack build --target web

Finally, the compiled module is imported into the main JavaScript file and its function is called just like any other JS function, after a one-time initialization.

// Import and run the WASM module
import init, { apply_grayscale_wasm } from './pkg/your_wasm_package.js';

async function run() {
  await init(); // Initialize the module

  // ... get image data from canvas ...

  // Call the super-fast Rust function!
  apply_grayscale_wasm(imageData.data);

  // ... put the data back on the canvas ...
}
run();