Promises are a JS mechanism to run code asynchronously. We currently do not support itJavascript is single-threaded, and code will crash if it tries to actually usebut can support cooperative multithreading using async/await and promises.
Spidermonkey exposes an API to provide our own "job queue" that can run these tasksbindings to allow running promises (code that currently tries to use Promises will crash).
This diff implements the necessary logic to support that, which is mostly two things:
- A JSContext* hook to dispatch promise queuing.
- Logic to run the dispatched jobs (aka the 'event loop').
However, doing that only allows asynchronous JS calls, which is not terribly useful by itself because everything remains single-threaded.
This diff also implements a simple interface to let JS wait on C++ threaded tasks, using the thread pool manager.
The logic is barebones and should perhaps be expended, but works. I've added fairly simple tests covering the above.
One particular inefficiency is that we iterate futures when calling RunJob, which could be inefficient if there are lots of pending futures.
Some notes:
- RunJobs() should be run manually in any context that supports Promises - It's probably a good idea to fail queuing jobs if the scriptinterface isn't supposed to run jobs
- The futures are passed to the script interface so that it knows to wait/cancel them when being destroyed. This looks a lot like Spidermonkey's `OffThreadPromiseTask` but they kind of assume JSContext lifetime. I think doing it manually is better.
WIP:
- I think the code should be moved from ScriptInterface to a 'ScriptTasks' class somewhere, probably still owned by the scriptInterface.
Future work:
- It would be nice to be able to run JS work in a thread manner, but that's more work.
This demonstrates a very simple one that calls the resolve job instantly when the asynchronous task ends.
Design questions:
- Is it a good idea to support asynchronous calls from Javascript? It might well lead to unpredictable lag.
- If so, when and where?
Notes:
- There is only a single jobqueue for a given runtime, so we'd have to share it between GUI, Sim and AI.
- The value is already embedded in the function somehow, and it just has to be called.