WebAssembly JSPI Gets a Simplified API in Chrome M126: What’s New and How to Use It

By ⚡ min read
<article> <p>WebAssembly’s JavaScript Promise Integration (JSPI) API has undergone a significant update with the release of Chrome M126. This new API simplifies the integration of asynchronous JavaScript operations into WebAssembly applications, making it easier for developers to bridge the gap between synchronous C/C++ code and the Promise-based world of the web. In this article, we explore the key changes, how to use the updated API with Emscripten, and what lies ahead for JSPI.</p> <h2 id="evolution-of-jspi">The Evolution of JSPI: Key Changes</h2> <p>The latest revision of JSPI introduces three major changes that streamline the API and improve developer experience. These changes were voted on by the Stacks sub-group of the WebAssembly Community Group in January 2024.</p><figure style="margin:20px 0"><img src="https://picsum.photos/seed/3829323583/800/450" alt="WebAssembly JSPI Gets a Simplified API in Chrome M126: What’s New and How to Use It" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px"></figcaption></figure> <h3 id="end-of-suspender-objects">1. End of Explicit Suspender Objects</h3> <p>Previously, JSPI required developers to manually create and manage <strong>Suspender</strong> objects to mark where a WebAssembly computation should be suspended when a Promise is returned. The new API eliminates this explicit handling. Instead, the JavaScript/WebAssembly boundary itself now serves as the delimiter for suspension. Specifically, the most recent call into a <em>wrapped</em> WebAssembly export determines the cut-off point for what gets suspended.</p> <p>This change means developers have slightly less fine-grained control over the exact suspension point. However, the trade-off is a significantly simpler API—no longer needing to worry about Suspender objects reduces boilerplate and potential errors. For most use cases, this automatic behavior is sufficient and welcome.</p> <h3 id="no-more-webassembly-function">2. No More WebAssembly.Function Constructor</h3> <p>Another major simplification is the removal of the <code>WebAssembly.Function</code> constructor from the JSPI wrapping process. Earlier versions required developers to create wrappers using <code>WebAssembly.Function</code>, which depended on the Type Reflection Proposal. The new API provides dedicated functions and constructors specifically for JSPI, removing that dependency.</p> <p>This change brings multiple benefits:</p> <ul> <li>It eliminates the reliance on the Type Reflection Proposal, which is still not universally supported.</li> <li>Tooling for JSPI becomes simpler because developers no longer need to explicitly reference WebAssembly function types.</li> </ul> <p>The removal of explicit Suspender objects made this simplification possible, as the type system no longer needs to account for custom suspender arguments.</p> <h3 id="suspending-only-on-promise-returns">3. Suspending Only on Promise Returns</h3> <p>A third change refines when a suspension actually occurs. In the old API, calling any JavaScript function from a suspending import would always suspend the WebAssembly execution, even if the JavaScript function did not return a Promise. The new API suspends <strong>only</strong> when the called JavaScript function actually returns a Promise.</p> <p>While this modification may appear to contradict some W3C TAG recommendations, it is a safe optimization. JSPI effectively occupies the role of the caller to a function that returns a Promise; therefore, it only needs to suspend when that Promise is actually returned. For most applications, this change has minimal impact, but it can significantly reduce unnecessary trips to the browser’s event loop, improving performance.</p> <h2 id="new-api-at-a-glance">The New API at a Glance</h2> <p>The core of the new JSPI API is a straightforward function that takes a WebAssembly export (typically a function) and converts it into a function that returns a JavaScript Promise. The signature looks like:</p> <pre><code>const asyncExport = WebAssembly.promising(wasmInstance.exports.someFunction);</code></pre> <p>This replaces the earlier pattern that required <code>WebAssembly.Function</code> and explicit Suspender objects. The resulting async export can be called from JavaScript just like any Promise-based function. Under the hood, JSPI handles suspension and resumption automatically based on the boundary rules described above.</p> <h2 id="using-jspi-with-emscripten">Using JSPI with Emscripten</h2> <p>Emscripten, the primary compiler for C/C++ to WebAssembly, has integrated JSPI support. To take advantage of the new API, you typically compile with the <code>-sASYNCIFY</code> flag and include the JSPI runtime support. The updated API in Chrome M126 works seamlessly with Emscripten’s existing async handling, but you may need to update your Emscripten version to the latest that incorporates the JSPI changes. Documentation and examples are available in the <a href="https://emscripten.org/docs/porting/asyncify.html">Emscripten Asyncify documentation</a>.</p> <h2 id="roadmap-future">Roadmap and Future of JSPI</h2> <p>The JSPI specification is still evolving. The changes in Chrome M126 represent the current consensus of the WebAssembly Community Group, but further refinements may come as use cases expand. The Stacks sub-group continues to explore additional scenarios, such as integration with workers and streaming compilation. Developers are encouraged to experiment with the new API and provide feedback to help shape the final specification.</p> <h2 id="conclusion">Conclusion</h2> <p>The new JSPI API in Chrome M126 marks a move toward greater simplicity and performance. By removing explicit Suspender objects, eliminating the <code>WebAssembly.Function</code> dependency, and intelligently suspending only when needed, the API becomes more accessible to developers. Whether you are porting legacy C/C++ code or building new WebAssembly applications that need to interact with asynchronous web APIs, JSPI provides a clean bridge. Start experimenting with Chrome M126 today and see how it can streamline your WebAssembly projects.</p> <p><em>For more details, see the original <a href="https://developer.chrome.com/blog/jspi-new-api">blog post</a> and the <a href="https://github.com/WebAssembly/js-promise-integration">JSPI specification</a>.</em></p> </article>