Iāve pushed a number of changes to properly support asynchronous programming with the WASM instance. The key is that next to Prolog.query()
, which returns an iterator for synchronous querying we now have a new method
Prolog.forEach(goal, [input], [on_answer])
Here, goal
and input
are handled as in Prolog.query
. on_answer
is a callback that is called on each answer with an object that represents the output bindings. For example
Prolog.forEach(member(X, List), {List: [1,2,3]},
(r) => console.log(r.X));
The browser remains responsive while this query is processed. The forEach
method returns a Promise. When resolved and there is an on_answer
, it passes the number of answers. If there is no on_answer
it passes the answers as an array. On a Prolog exception the Promise is rejected.
Except that I am not sure about the name (forEach), this seems a viable approach to deal with long running queries.
The second change is to the Prolog predicate js_yield/2. This used to exchange strings. Now it exchanges arbitrary data and it allows the object to yield on to be a Promise. This allows for fancy queries such as below.
?- FP := fetch("test.pl"), js_yield(FP, Response),
TP := Response.text(), js_yield(TP, T).
FP = <js_Promise>(4),
Response = <js_Response>(5),
TP = <js_Promise>(6),
T = '% :- debug(js) ...'.
It also provides a clean extensible interface for adding other asynchronous operations. The Prolog sleep/1 replacement on WASM now uses this interface, removing this code from the core interface.
#wasm_demo is updated.