WebAssembly and JavaScript interoperability is one of its core features, implemented through import/export mechanisms:
1. Import JavaScript Functions into WebAssembly WebAssembly can import JavaScript functions and call them internally:
javascript// JavaScript code const importObject = { env: { log: (value) => console.log(value), add: (a, b) => a + b, currentTime: () => Date.now() } }; // Load WebAssembly module WebAssembly.instantiateStreaming(fetch('module.wasm'), importObject) .then(results => { // WebAssembly module can call imported functions });
2. Export WebAssembly Functions to JavaScript WebAssembly modules can export functions for JavaScript to call:
javascript// After loading WebAssembly module const wasmModule = results.instance; // Call exported functions const result = wasmModule.exports.add(10, 20); console.log(result); // 30
3. Memory Sharing JavaScript and WebAssembly can share memory:
javascript// Create shared memory const memory = new WebAssembly.Memory({ initial: 10, maximum: 100 }); // Pass memory to WebAssembly const importObject = { env: { memory: memory } }; // JavaScript can access memory const buffer = new Uint8Array(memory.buffer); buffer[0] = 42; // WebAssembly can also access the same memory
4. Data Type Conversion Data type conversion between JavaScript and WebAssembly:
| JavaScript | WebAssembly |
|---|---|
| Number | f32, f64, i32, i64 |
| BigInt | i64 |
| TypedArray | Memory view |
| Array | Manual conversion required |
javascript// JavaScript calls WebAssembly function const result = wasmModule.exports.processData( 42, // i32 3.14, // f64 BigInt(123) // i64 ); // WebAssembly returns data const wasmResult = wasmModule.exports.getData(); const view = new Uint32Array(memory.buffer, offset, length);
5. Complex Data Structures For complex data structures, manual serialization and deserialization is required:
javascript// Pass object function sendObjectToWasm(obj) { const jsonString = JSON.stringify(obj); const encoder = new TextEncoder(); const encoded = encoder.encode(jsonString); // Write to WebAssembly memory const buffer = new Uint8Array(memory.buffer); buffer.set(encoded, 0); // Call WebAssembly function wasmModule.exports.processObject(0, encoded.length); } // Receive object from WebAssembly function receiveObjectFromWasm(offset, length) { const buffer = new Uint8Array(memory.buffer); const slice = buffer.slice(offset, offset + length); const decoder = new TextDecoder(); const jsonString = decoder.decode(slice); return JSON.parse(jsonString); }
6. Async Operations WebAssembly itself doesn't support async, but can be implemented through JavaScript:
javascript// WebAssembly calls async JavaScript function const importObject = { env: { fetchData: async (url) => { const response = await fetch(url); return response; } } };
7. Error Handling Handle errors between WebAssembly and JavaScript:
javascripttry { const result = wasmModule.exports.mightFail(); } catch (error) { console.error('WebAssembly error:', error); }
8. Performance Optimization
- Reduce the number of cross-boundary calls
- Use shared memory to avoid data copying
- Batch process data
- Use TypedArray for efficient binary data transfer
9. Best Practices
- Clearly define import/export interfaces
- Use TypeScript type definitions for type safety
- Design data exchange formats reasonably
- Balance performance and development experience
- Use tools to simplify interoperability (e.g., wasm-bindgen)