WebAssembly JavaScript Interface

An effective way to learn WASM from JS (or JS from WASM) is to go through the official specification in detail.

WebAssembly JavaScript Interface defines JavaScript classes and objects for accessing WebAssembly from within JavaScript, including methods for validation, compilation, instantiation, and classes for representing and manipulating imports and exports as JavaScript objects.

Sample

Reference

WebAssembly.instantiate

chapter_wasm_js_api/sample/sample.wat

(module
    (import "js" "import1" (func $i1))
    (import "js" "import2" (func $i2))
    (func $main (call $i1))
    (start $main)
    (func (export "f") (call $i2))
)
$ wat2wasm sample.wat
$ hexdump -C sample.wasm
00000000  00 61 73 6d 01 00 00 00  01 04 01 60 00 00 02 1b  |.asm.......`....|
00000010  02 02 6a 73 07 69 6d 70  6f 72 74 31 00 00 02 6a  |..js.import1...j|
00000020  73 07 69 6d 70 6f 72 74  32 00 00 03 03 02 00 00  |s.import2.......|
00000030  07 05 01 01 66 00 03 08  01 02 0a 0b 02 04 00 10  |....f...........|
00000040  00 0b 04 00 10 01 0b                              |.......|
00000047

chapter_wasm_js_api/sample/sample.js

var importObj = {
    js: {
        import1: () => console.log("hello,"),
        import2: () => console.log("world!")
    }
};
fetch('/chapter_wasm_js_api/sample/sample.wasm').then(response =>
    response.arrayBuffer()
).then(buffer =>
    WebAssembly.instantiate(buffer, importObj)
).then(({ module, instance }) =>
    instance.exports.f()
);

The result is in console log.

WebAssembly.validate | compile | instantiate

Reference

chapter_wasm_js_api/sample/validate_compile_instantiate.js

var importObj = {
    js: {
        import1: () => console.log("hello,"),
        import2: () => console.log("world!")
    }
};

fetch('/chapter_wasm_js_api/sample/sample.wasm').then(response => {
    console.log({ response });
    return response.arrayBuffer();
}).then(buffer => {
    console.log({ buffer });
    if (WebAssembly.validate(buffer)) {
        return WebAssembly.compile(buffer);
    }
    else {
        throw 'invalid WASM';
    }
}).then(module => {
    console.log({ module });
    return WebAssembly.instantiate(module, importObj);
}).then(instance => {
    console.log({ instance });
    const { exports } = instance;
    const { f } = exports;
    f();
}).catch((error) => {
    console.error(error);
});

The result is in console log.

Async/await instantiate

chapter_wasm_js_api/sample/async_instantiate.js

(async () => {
    const importObj1 = {
        js: {
            import1: () => console.log("From importObj1"),
            import2: () => console.log("hello world!")
        }
    };

    const importObj2 = {
        js: {
            import1: () => console.log("From importObj2"),
            import2: () => console.log("hello world!")
        }
    };

    const response = await fetch('/chapter_wasm_js_api/sample/sample.wasm');
    console.log({ response });
    const buffer = await response.arrayBuffer();
    console.log({ buffer });

    if (WebAssembly.validate(buffer)) {
        const module = await WebAssembly.compile(buffer);
        console.log({ module });

        const instance1 = await WebAssembly.instantiate(module, importObj1);
        instance1.exports.f();

        const instance2 = await WebAssembly.instantiate(module, importObj2);
        instance2.exports.f();

    }
    else {
        console.error('invalid WASM');
    }
})();

The result is in console log.