Sign in Join
Wiki copytemporary

WebAssembly/JS-Promise Integration: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: WebAssembly/JS-Promise Integration

OldNewLine
1+The WebAssembly JavaScript-Promise Integration Proposal is a proposed extension to the browser JavaScript API: [1](https://github.com/WebAssembly/js-promise-integration/blob/main/proposals/js-promise-integration/Overview.md) It allows calling asynchronous JavaScript functions from WebAssembly code as if they are synchronous, as well as calling WebAssembly functions asynchronously from JavaScript, even though they are implemented as synchronous.
2+
3+# Browser support
4+
5+There is currently experimental support implemented in Chrome, Chromium and Edge. So far, browser support is only implemented on the x86_64 and aarch64 platforms. Minimum Chrome versions that support it are 110.0.5473.0 (macOS) / 110.0.5469.0 (Windows, Android) / 110.0.5478.4 (Linux). As an experimental feature, it is disabled by default. To enable it, go to the URL:
6+
7+[`chrome://flags`](chrome://flags)
8+
9+Search for "Experimental WebAssembly JavaScript Promise Integration (JSPI)". Click on the box, select "enable", then restart the browser to enable the feature.
10+
11+# Free Pascal support
12+
13+Free Pascal support for this extension was merged into the main FPC branch on Jun 26 2023.
14+
15+# Free Pascal language extensions
16+
17+## Suspending externals
18+
19+Suspending externals allows calling JavaScript functions that are run asynchronously on the JavaScript side, even though they are called as if they are synchronous on the WebAssembly side. Example:
20+
21+`function compute_delta: double; external 'js' suspending;`
22+
23+Or:
24+
25+`function compute_delta: double; external 'js' suspending first;`
26+
27+Now we can implement this function asynchronously on the JavaScript side:
28+
29+`var compute_delta = () => `\
30+`  fetch('`[`https://example.com/data.txt`](https://example.com/data.txt)`')`\
31+`    .then(res => res.text())`\
32+`    .then(txt => parseFloat(txt));`
33+
34+We then prepare the asynchronous function for use as a suspending WebAssembly external, like this:
35+
36+`var suspending_compute_delta = new WebAssembly.Function(`\
37+`  {parameters:[externref],results:['f64']},`\
38+`  compute_delta,`\
39+`  {suspending:"first"}`\
40+`)`
41+
42+We can the use this to form the complete import object:
43+
44+`var importObj = {js: {`\
45+`    compute_delta:suspending_compute_delta}};`
46+
47+Note the extra *externref* parameter, as well as the extra attribute *{suspending:"first"}*. The extra *externref* parameter is automatically added, when a function is declared 'suspending'. It contains a special suspender object that is used internally by the WebAssembly JavaScript Promise Integration extension. For more details, see the [spec](https://github.com/WebAssembly/js-promise-integration/blob/main/proposals/js-promise-integration/Overview.md#specification). Free Pascal automatically adds the suspender as an extra first parameter for functions that are declared external suspending. There's also an option to add it as a last parameter. In this case, the declaration in Free Pascal needs to be changed to:
48+
49+`function compute_delta: double; external 'js' suspending last;`
50+
51+And on the JavaScript side, the value of the *suspending* attribute needs to be changed to: *{suspending:"last"}*.
52+
53+## Promising exports
54+
55+In order for calls to suspending functions to work, WebAssembly code execution must be entered via an export, marked as 'promising'. Example:
56+
57+`var`\
58+`  state: double;`\
59+
60+`function update_state: double;`\
61+`begin`\
62+`  state := state + compute_delta;  // this calls the suspending function 'compute_delta'`\
63+`  update_state := state;`\
64+`end;`\
65+
66+`exports`\
67+`  update_state promising;`
68+
69+Once again, a *promising* export has an extra externref parameter automatically added. Here's how it can be wrapper correctly on the JavaScript side:
70+
71+`var sampleModule = WebAssembly.instantiate(demoBuffer,importObj);`\
72+`var update_state = new WebAssembly.function(`\
73+`  {parameters:[], results:['externref']},`\
74+`  sampleModule.exports.update_state_export,`\
75+`  {promising : "first"})`
76+
77+Alternatively, you can use *promising last*. If you export it like this in Pascal:
78+
79+`exports`\
80+`  update_state promising last;`
81+
82+Then you can use *{promising : "last"}* instead of *{promising : "first"}* in JavaScript.
83+
84+# See Also
85+
86+- [A working example](https://www.freepascal.org/~michael/pas2js-demos/jspi/)
87+- [JavaScript-Promise Integration Proposal](https://github.com/WebAssembly/js-promise-integration/blob/main/proposals/js-promise-integration/Overview.md)
88+- [Introducing the WebAssembly JavaScript Promise Integration API](https://v8.dev/blog/jspi)
89+- [[WebAssembly]]
90+
91+---
92+*From the Free Pascal wiki, page "WebAssembly/JS-Promise Integration", as it stood on 2023-06-26 after a change by Nickysn, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
93+Category: WebAssembly

Back to history