Is there an async sleep anywhere in Promises and Futures - The `wasm-bindgen` Guide ?
Normally, I would use setTimeout() - Web APIs | MDN , but I am looking for a async rather than timeout based solution.
Is there an async sleep anywhere in Promises and Futures - The `wasm-bindgen` Guide ?
Normally, I would use setTimeout() - Web APIs | MDN , but I am looking for a async rather than timeout based solution.
For what it's worth, you can pretty trivially convert a setTimeout()
based sleep into something async.
use futures::channel::oneshot;
use std::time::Duration;
fn setTimeout(duration: Duration, callback: impl FnOnce()) {
todo!();
}
async fn sleep(duration: Duration) {
let (send, recv) = oneshot::channel();
setTimeout(duration, move || {
let _ = send.send(());
});
recv.await;
}
@Michael-F-Bryan : Very cool technique. Can we do this without the channel ?
In JS, one technique for settimeout -> async sleep is:
// untested, copied from internet
waitFor = delay => new Promise(resolved => setTimeout(resolve, delay));
await waitFor(...);
I'm wondering if there is a 'direct' translation of this via wasm_bindgen_futures, which does not need the intermediate oneshot::channel.
I'm just using the channel as a cheap way to write a future - it's in no way necessary for this to work. If you squint, the sender.send()
lets us delegate to Waker::wake()
to tell whatever is polling our sleep()
function that it's time to wake up.
You could probably create your own Future
implementation, possibly taking inspiration from the implementation for wasm_bindgen_futures::JsFuture
to see how it wires up resolve
and reject
.
The important bit is line 149 where we take the Wake
handle that was stashed away in a previous poll()
and call its wake()
method.
That is instructive but not the direction I was thinking. The following code does not compile yet, but I am wondering if it can be made to work:
pub async fn sleep(delay: u32) {
let cb = |resolve: js_sys::Function, reject: js_sys::Function| {
web_sys::window()
.unwrap()
.set_timeout_with_callback_and_timeout_and_arguments_0(resolve, delay);};
let p = js_sys::Promise::new(cb);
p.await}
pub async fn sleep(delay: i32) {
let mut cb = |resolve: js_sys::Function, reject: js_sys::Function| {
web_sys::window()
.unwrap()
.set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, delay);};
let p = js_sys::Promise::new(&mut cb);
wasm_bindgen_futures::JsFuture::from(p).await.unwrap();}
compiles and appears to work.
I have no idea how safe/unsafe this is to use. Insights anyone? [In particular, I lack the understanding of what preconditions the JS / Rust async 'border' have of each other, so I have no idea if I'm breaking any assumptions here.]
(Caveat: I'm very new to Rust/Wasm.)
I've got code with a dependency on async_std and wasm-bindgen-futures in Cargo.toml that does basically the following, which appears to be working fine:
async fn myfunc() {
...
let delay = 1000;
async_std::task::sleep(Duration::from_millis(delay as u64)).await;
...
}