perspective_viewer/utils/browser/request_animation_frame.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
use ::futures::channel::oneshot::*;
use perspective_js::utils::{global, *};
use wasm_bindgen::prelude::*;
/// An `async` version of `queueMicrotask()`, curiously absent from [`web_sys`].
pub async fn await_queue_microtask() -> ApiResult<()> {
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = Window)]
type QMWindow;
#[wasm_bindgen(catch, method, structural, js_class = "Window", js_name = queueMicrotask)]
fn queue_microtask(this: &QMWindow, callback: &::js_sys::Function) -> Result<i32, JsValue>;
}
let (sender, receiver) = channel::<()>();
let jsfun = Closure::once_into_js(move || sender.send(()).unwrap());
js_sys::global()
.dyn_into::<QMWindow>()
.unwrap()
.queue_microtask(jsfun.unchecked_ref())?;
Ok(receiver.await?)
}
/// An `async` version of `requestAnimationFrame()`, which resolves on the next
/// animation frame.
pub async fn request_animation_frame() {
let (sender, receiver) = channel::<()>();
let jsfun = Closure::once_into_js(move || sender.send(()).unwrap());
global::window()
.request_animation_frame(jsfun.unchecked_ref())
.unwrap();
receiver.await.unwrap()
}
/// An `async` which awaits the browser's `load` event, which is automatically
/// bypassed if `document.readyState` indicates this has already occurred.
pub async fn await_dom_loaded() -> ApiResult<()> {
let state = global::document().ready_state();
if state == "complete" || state == "loaded" {
Ok(())
} else {
let (sender, receiver) = channel::<()>();
let jsfun = Closure::once_into_js(move || sender.send(()).unwrap());
global::window().add_event_listener_with_callback("load", jsfun.unchecked_ref())?;
Ok(receiver.await?)
}
}
/// An `async` version of `set_timeout`, which resolves in `timeout`
/// milliseconds
pub async fn set_timeout(timeout: i32) -> ApiResult<()> {
let (sender, receiver) = channel::<()>();
let jsfun = Closure::once_into_js(move || {
let _ = sender.send(());
});
global::window()
.set_timeout_with_callback_and_timeout_and_arguments_0(jsfun.unchecked_ref(), timeout)?;
Ok(receiver.await?)
}