js_sys
exposes JavaScript Promise
via a function pub fn new(cb: &mut dyn FnMut(Function, Function)) -> Promise;
. Per my reading of the MDN documentation, there's nothing suggesting that the executor function will be called more than once, yet js_sys
exposes it as an FnMut
instead of an FnOnce
.
Because of this, I can't wrap my head around a simple task, such as sending a message to myself in the future via a channel. Ideally, the sender
half of the channel would be moved into the closure and Promise::new
would accept an FnOnce
.
async func send_to_future_self() {
use std::sync::mpsc::{Sender, Receiver, channel};
let (sender, receiver) = channel().split();
// Schedule sending a message in the future
// Option A: Move `sender` --> The closure becomes `FnOnce` because it consumes `sender`
// Option B: Reference `sender` --> Then the borrow outlives `sender`'s lifetime
let mut sleep_100 = move?? |accept: Function, _reject: Function| {
// This Rust closure is exported to Javascript...
let callback = Closure::__??__(move?? || {
// Send a message via the channel
sender.send(()).unwrap();
let result = js_sys::Array::new();
// Doesn't matter what value is passed here, it's just for synchronization
result.push(&JsValue::from(true));
accept.apply(&JsValue::undefined(), &result).unwrap();
});
web_sys::window().unwrap()
.set_timeout_with_callback_and_timeout_and_arguments_0(
callback.as_ref().unchecked_ref(),
100
).unwrap();
// ... so intentionally forget it, otherwise it will be dropped at the end of this block
// despite JS still referring to it.
callback.forget();
};
// Convert JS Promise into a Rust future
// This wants an FnMut(Function, Function)
let future: JsFuture = js_sys::Promise::new(&mut sleep_100).into();
let _ = future.await;
receiver.try_recv().unwrap();
}