As some have discovered, I picked up the in-browser version of SWI-Prolog. See https://swi-prolog.discourse.group/t/wiki-discussion-swi-prolog-in-the-browser-using-wasm.
We can do the same (I guess), but we also have two alternatives. One was created after discussion with @matthijs: yield from a foreign predicate, i.e., a foreign predicate can ask the VM to return control to its caller, allowing the VM to be resumed later. The other is delimited continuations that do something similar, but I think they won’t work for this because control remains in the Prolog VM.
The C side looks like this:
let rc = prolog.call("mygoal")) if ( (url = is_fetch_request(rc)) ) fetch(url) .then( (response) => response.json()) .then( (data) => prolog.resume(data)); // handle other things we might be waiting for
Note that on the long run we can possibly maintain various threads of control in Prolog waiting for different events using this as first level and delimited continuations as secondary level