Asynchronous JavaScript
By default, rustyscript can resolve most asynchronous javascript, including promises, by blocking the current thread.
In many cases, however, this will not be sufficient.
For example, handling ongoing background tasks, dealing with promises, or running async functions in parallel.
To this end, many functions will have _async
and _immediate
variants.
_async
_async
functions will return a Future that that resolves when:
- The event loop is resolved, and
- If the value is a promise, the promise is resolved
For example call_function_async
will return a Future that resolves when the function call completes,
And, if the function returns a promise, when the promise is resolved.
_immediate
_immediate
functions will return a value immediately, but will not resolve promises or advance the event loop.
- Promises can be returned by specifying the return type as
js_value::Promise
- The event loop should be run using [
Runtime::await_event_loop
]
For example, call_function_immediate
on a function returning a promise, will return a js_value::Promise<T>
object, which can be resolved later.
You can turn Promise<T>
into Future<Output = T>
by calling Promise::into_future
This allows you to export multiple concurrent promises without borrowing the runtime mutably
You can also use Promise::into_value
to block until the promise is resolved, and get the value.
A long-form example can be found here
Futures, with async functions
In the example below, we define a simple async function in javascript, and call it from rust.
The runtime's own tokio runtime is used to resolve the future.
The event loop, and the implicit promise resolution, is handled by the runtime, transparently.
This is the simplest way to use async functions.
use rustyscript::{Error, Module, Runtime}; fn main() -> Result<(), Error> { let module = Module::new( "test.js", " export const my_func = async () => 42; ", ); // Create a new runtime // We don't need to create a tokio runtime, as the runtime will create one for us let mut runtime = Runtime::new(Default::default())?; let handle = runtime.load_module(&module)?; let tokio_runtime = runtime.tokio_runtime(); // Call the function, and await the result let value: u32 = tokio_runtime.block_on(async { runtime .call_function_async(Some(&handle), "my_func", &()) .await })?; assert_eq!(value, 32); Ok(()) }
Another way is with js_value::Promise
Normally, calling a function would resolve the promise. So we need to use call_function_immediate
instead.
use rustyscript::{js_value::Promise, Error, Module, Runtime}; fn main() -> Result<(), Error> { let module = Module::new( "test.js", " export const my_func = async () => 42; ", ); // Create a new runtime let mut runtime = Runtime::new(Default::default())?; let handle = runtime.load_module(&module)?; // Call the function, and get the promise let promise: Promise<u32> = runtime.call_function_immediate(Some(&handle), "my_func", &())?; // Resolve the promise // You could instead call `into_future` here, and await it, for a non-blocking version let value = promise.into_value(&mut runtime)?; assert_eq!(value, 42); Ok(()) }
Background Tasks
Sometimes, a module may begin background tasks, which would tie up the event loop for a long time, causing the async
and blocking
functions to hang.
In this case, you can use one of the following methods:
Combined with the immediate
variants of most functions, this will allow you full control over execution of the event loop.
See this example for a demonstration.
Threading
The last way to handle async functions is to use a separate thread.
See Multi-Threading for more information.