Web: implement WaitUntilStrategy (#3739)
This commit is contained in:
parent
b4e83a5966
commit
3e6092b8ed
12 changed files with 231 additions and 14 deletions
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
|
|
@ -226,3 +226,19 @@ jobs:
|
||||||
command: check
|
command: check
|
||||||
log-level: error
|
log-level: error
|
||||||
arguments: --all-features --target ${{ matrix.platform.target }}
|
arguments: --all-features --target ${{ matrix.platform.target }}
|
||||||
|
|
||||||
|
swc:
|
||||||
|
name: Minimize JavaScript
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Install SWC
|
||||||
|
run: sudo npm i -g @swc/cli
|
||||||
|
- name: Run SWC
|
||||||
|
run: |
|
||||||
|
swc src/platform_impl/web/web_sys/worker.js -o src/platform_impl/web/web_sys/worker.min.js
|
||||||
|
- name: Check for diff
|
||||||
|
run: |
|
||||||
|
[[ -z $(git status -s) ]]
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,8 +3,5 @@ target/
|
||||||
rls/
|
rls/
|
||||||
.vscode/
|
.vscode/
|
||||||
*~
|
*~
|
||||||
*.wasm
|
|
||||||
*.ts
|
|
||||||
*.js
|
|
||||||
#*#
|
#*#
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
||||||
12
.swcrc
Normal file
12
.swcrc
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"minify": true,
|
||||||
|
"jsc": {
|
||||||
|
"target": "es2022",
|
||||||
|
"minify": {
|
||||||
|
"compress": {
|
||||||
|
"unused": true
|
||||||
|
},
|
||||||
|
"mangle": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -285,6 +285,7 @@ features = [
|
||||||
'AbortController',
|
'AbortController',
|
||||||
'AbortSignal',
|
'AbortSignal',
|
||||||
'Blob',
|
'Blob',
|
||||||
|
'BlobPropertyBag',
|
||||||
'console',
|
'console',
|
||||||
'CssStyleDeclaration',
|
'CssStyleDeclaration',
|
||||||
'Document',
|
'Document',
|
||||||
|
|
@ -320,6 +321,7 @@ features = [
|
||||||
'VisibilityState',
|
'VisibilityState',
|
||||||
'Window',
|
'Window',
|
||||||
'WheelEvent',
|
'WheelEvent',
|
||||||
|
'Worker',
|
||||||
'Url',
|
'Url',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,11 @@ changelog entry.
|
||||||
|
|
||||||
- On Web, add `EventLoopExtWebSys::(set_)poll_strategy()` to allow setting
|
- On Web, add `EventLoopExtWebSys::(set_)poll_strategy()` to allow setting
|
||||||
control flow strategies before starting the event loop.
|
control flow strategies before starting the event loop.
|
||||||
|
- On Web, add `WaitUntilStrategy`, which allows to set different strategies for
|
||||||
|
`ControlFlow::WaitUntil`. By default the Prioritized Task Scheduling API is
|
||||||
|
used, with a fallback to `setTimeout()` with a trick to circumvent throttling
|
||||||
|
to 4ms. But an option to use a Web worker to schedule the timer is available
|
||||||
|
as well, which commonly prevents any throttling when the window is not focused.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,20 @@ pub trait EventLoopExtWebSys {
|
||||||
///
|
///
|
||||||
/// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
|
/// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
|
||||||
fn poll_strategy(&self) -> PollStrategy;
|
fn poll_strategy(&self) -> PollStrategy;
|
||||||
|
|
||||||
|
/// Sets the strategy for [`ControlFlow::WaitUntil`].
|
||||||
|
///
|
||||||
|
/// See [`WaitUntilStrategy`].
|
||||||
|
///
|
||||||
|
/// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||||
|
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy);
|
||||||
|
|
||||||
|
/// Gets the strategy for [`ControlFlow::WaitUntil`].
|
||||||
|
///
|
||||||
|
/// See [`WaitUntilStrategy`].
|
||||||
|
///
|
||||||
|
/// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||||
|
fn wait_until_strategy(&self) -> WaitUntilStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtWebSys for EventLoop<T> {
|
impl<T> EventLoopExtWebSys for EventLoop<T> {
|
||||||
|
|
@ -213,6 +227,14 @@ impl<T> EventLoopExtWebSys for EventLoop<T> {
|
||||||
fn poll_strategy(&self) -> PollStrategy {
|
fn poll_strategy(&self) -> PollStrategy {
|
||||||
self.event_loop.poll_strategy()
|
self.event_loop.poll_strategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
||||||
|
self.event_loop.set_wait_until_strategy(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
||||||
|
self.event_loop.wait_until_strategy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ActiveEventLoopExtWebSys {
|
pub trait ActiveEventLoopExtWebSys {
|
||||||
|
|
@ -230,6 +252,20 @@ pub trait ActiveEventLoopExtWebSys {
|
||||||
/// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
|
/// [`ControlFlow::Poll`]: crate::event_loop::ControlFlow::Poll
|
||||||
fn poll_strategy(&self) -> PollStrategy;
|
fn poll_strategy(&self) -> PollStrategy;
|
||||||
|
|
||||||
|
/// Sets the strategy for [`ControlFlow::WaitUntil`].
|
||||||
|
///
|
||||||
|
/// See [`WaitUntilStrategy`].
|
||||||
|
///
|
||||||
|
/// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||||
|
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy);
|
||||||
|
|
||||||
|
/// Gets the strategy for [`ControlFlow::WaitUntil`].
|
||||||
|
///
|
||||||
|
/// See [`WaitUntilStrategy`].
|
||||||
|
///
|
||||||
|
/// [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||||
|
fn wait_until_strategy(&self) -> WaitUntilStrategy;
|
||||||
|
|
||||||
/// Async version of [`ActiveEventLoop::create_custom_cursor()`] which waits until the
|
/// Async version of [`ActiveEventLoop::create_custom_cursor()`] which waits until the
|
||||||
/// cursor has completely finished loading.
|
/// cursor has completely finished loading.
|
||||||
fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture;
|
fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture;
|
||||||
|
|
@ -250,6 +286,16 @@ impl ActiveEventLoopExtWebSys for ActiveEventLoop {
|
||||||
fn poll_strategy(&self) -> PollStrategy {
|
fn poll_strategy(&self) -> PollStrategy {
|
||||||
self.p.poll_strategy()
|
self.p.poll_strategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
||||||
|
self.p.set_wait_until_strategy(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
||||||
|
self.p.wait_until_strategy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Strategy used for [`ControlFlow::Poll`][crate::event_loop::ControlFlow::Poll].
|
/// Strategy used for [`ControlFlow::Poll`][crate::event_loop::ControlFlow::Poll].
|
||||||
|
|
@ -278,6 +324,29 @@ pub enum PollStrategy {
|
||||||
Scheduler,
|
Scheduler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strategy used for [`ControlFlow::WaitUntil`][crate::event_loop::ControlFlow::WaitUntil].
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub enum WaitUntilStrategy {
|
||||||
|
/// Uses the [Prioritized Task Scheduling API] to queue the next event loop. If not available
|
||||||
|
/// this will fallback to [`setTimeout()`].
|
||||||
|
///
|
||||||
|
/// This strategy is commonly not affected by browser throttling unless the window is not
|
||||||
|
/// focused.
|
||||||
|
///
|
||||||
|
/// This is the default strategy.
|
||||||
|
///
|
||||||
|
/// [Prioritized Task Scheduling API]: https://developer.mozilla.org/en-US/docs/Web/API/Prioritized_Task_Scheduling_API
|
||||||
|
/// [`setTimeout()`]: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
|
||||||
|
#[default]
|
||||||
|
Scheduler,
|
||||||
|
/// Equal to [`Scheduler`][Self::Scheduler] but wakes up the event loop from a [worker].
|
||||||
|
///
|
||||||
|
/// This strategy is commonly not affected by browser throttling regardless of window focus.
|
||||||
|
///
|
||||||
|
/// [worker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
|
||||||
|
Worker,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CustomCursorExtWebSys {
|
pub trait CustomCursorExtWebSys {
|
||||||
/// Returns if this cursor is an animation.
|
/// Returns if this cursor is an animation.
|
||||||
fn is_animation(&self) -> bool;
|
fn is_animation(&self) -> bool;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::application::ApplicationHandler;
|
||||||
use crate::error::EventLoopError;
|
use crate::error::EventLoopError;
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
||||||
use crate::platform::web::{ActiveEventLoopExtWebSys, PollStrategy};
|
use crate::platform::web::{ActiveEventLoopExtWebSys, PollStrategy, WaitUntilStrategy};
|
||||||
|
|
||||||
use super::{backend, device, window};
|
use super::{backend, device, window};
|
||||||
|
|
||||||
|
|
@ -85,6 +85,14 @@ impl<T> EventLoop<T> {
|
||||||
pub fn poll_strategy(&self) -> PollStrategy {
|
pub fn poll_strategy(&self) -> PollStrategy {
|
||||||
self.elw.poll_strategy()
|
self.elw.poll_strategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
||||||
|
self.elw.set_wait_until_strategy(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
||||||
|
self.elw.wait_until_strategy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
|
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::event::{
|
||||||
WindowEvent,
|
WindowEvent,
|
||||||
};
|
};
|
||||||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||||
use crate::platform::web::PollStrategy;
|
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
||||||
use crate::platform_impl::platform::backend::EventListenerHandle;
|
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||||
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
||||||
use crate::platform_impl::platform::window::Inner;
|
use crate::platform_impl::platform::window::Inner;
|
||||||
|
|
@ -43,6 +43,7 @@ pub struct Execution {
|
||||||
proxy_spawner: WakerSpawner<Weak<Self>>,
|
proxy_spawner: WakerSpawner<Weak<Self>>,
|
||||||
control_flow: Cell<ControlFlow>,
|
control_flow: Cell<ControlFlow>,
|
||||||
poll_strategy: Cell<PollStrategy>,
|
poll_strategy: Cell<PollStrategy>,
|
||||||
|
wait_until_strategy: Cell<WaitUntilStrategy>,
|
||||||
exit: Cell<bool>,
|
exit: Cell<bool>,
|
||||||
runner: RefCell<RunnerEnum>,
|
runner: RefCell<RunnerEnum>,
|
||||||
suspended: Cell<bool>,
|
suspended: Cell<bool>,
|
||||||
|
|
@ -149,6 +150,7 @@ impl Shared {
|
||||||
proxy_spawner,
|
proxy_spawner,
|
||||||
control_flow: Cell::new(ControlFlow::default()),
|
control_flow: Cell::new(ControlFlow::default()),
|
||||||
poll_strategy: Cell::new(PollStrategy::default()),
|
poll_strategy: Cell::new(PollStrategy::default()),
|
||||||
|
wait_until_strategy: Cell::new(WaitUntilStrategy::default()),
|
||||||
exit: Cell::new(false),
|
exit: Cell::new(false),
|
||||||
runner: RefCell::new(RunnerEnum::Pending),
|
runner: RefCell::new(RunnerEnum::Pending),
|
||||||
suspended: Cell::new(false),
|
suspended: Cell::new(false),
|
||||||
|
|
@ -688,6 +690,7 @@ impl Shared {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
_timeout: backend::Schedule::new_with_duration(
|
_timeout: backend::Schedule::new_with_duration(
|
||||||
|
self.wait_until_strategy(),
|
||||||
self.window(),
|
self.window(),
|
||||||
move || cloned.resume_time_reached(start, end),
|
move || cloned.resume_time_reached(start, end),
|
||||||
delay,
|
delay,
|
||||||
|
|
@ -800,6 +803,14 @@ impl Shared {
|
||||||
self.0.poll_strategy.get()
|
self.0.poll_strategy.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
||||||
|
self.0.wait_until_strategy.set(strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
||||||
|
self.0.wait_until_strategy.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
||||||
self.0.proxy_spawner.waker()
|
self.0.proxy_spawner.waker()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::event::{
|
||||||
};
|
};
|
||||||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||||
use crate::keyboard::ModifiersState;
|
use crate::keyboard::ModifiersState;
|
||||||
use crate::platform::web::{CustomCursorFuture, PollStrategy};
|
use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy};
|
||||||
use crate::platform_impl::platform::cursor::CustomCursor;
|
use crate::platform_impl::platform::cursor::CustomCursor;
|
||||||
use crate::platform_impl::platform::r#async::Waker;
|
use crate::platform_impl::platform::r#async::Waker;
|
||||||
use crate::window::{
|
use crate::window::{
|
||||||
|
|
@ -682,6 +682,14 @@ impl ActiveEventLoop {
|
||||||
self.runner.poll_strategy()
|
self.runner.poll_strategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
|
||||||
|
self.runner.set_wait_until_strategy(strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wait_until_strategy(&self) -> WaitUntilStrategy {
|
||||||
|
self.runner.wait_until_strategy()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
||||||
self.runner.waker()
|
self.runner.waker()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
use js_sys::{Function, Object, Promise, Reflect};
|
use js_sys::{Array, Function, Object, Promise, Reflect};
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_bindgen::closure::Closure;
|
use wasm_bindgen::closure::Closure;
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
use web_sys::{AbortController, AbortSignal, MessageChannel, MessagePort};
|
use web_sys::{
|
||||||
|
AbortController, AbortSignal, Blob, BlobPropertyBag, MessageChannel, MessagePort, Url, Worker,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::platform::web::PollStrategy;
|
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Schedule {
|
pub struct Schedule {
|
||||||
|
|
@ -29,6 +31,7 @@ enum Inner {
|
||||||
port: MessagePort,
|
port: MessagePort,
|
||||||
_timeout_closure: Closure<dyn FnMut()>,
|
_timeout_closure: Closure<dyn FnMut()>,
|
||||||
},
|
},
|
||||||
|
Worker(MessagePort),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Schedule {
|
impl Schedule {
|
||||||
|
|
@ -45,14 +48,24 @@ impl Schedule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_duration<F>(window: &web_sys::Window, f: F, duration: Duration) -> Schedule
|
pub fn new_with_duration<F>(
|
||||||
|
strategy: WaitUntilStrategy,
|
||||||
|
window: &web_sys::Window,
|
||||||
|
f: F,
|
||||||
|
duration: Duration,
|
||||||
|
) -> Schedule
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(),
|
F: 'static + FnMut(),
|
||||||
{
|
{
|
||||||
if has_scheduler_support(window) {
|
match strategy {
|
||||||
Self::new_scheduler(window, f, Some(duration))
|
WaitUntilStrategy::Scheduler => {
|
||||||
} else {
|
if has_scheduler_support(window) {
|
||||||
Self::new_timeout(window.clone(), f, Some(duration))
|
Self::new_scheduler(window, f, Some(duration))
|
||||||
|
} else {
|
||||||
|
Self::new_timeout(window.clone(), f, Some(duration))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WaitUntilStrategy::Worker => Self::new_worker(f, duration),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +168,44 @@ impl Schedule {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_worker<F>(f: F, duration: Duration) -> Schedule
|
||||||
|
where
|
||||||
|
F: 'static + FnMut(),
|
||||||
|
{
|
||||||
|
thread_local! {
|
||||||
|
static URL: ScriptUrl = ScriptUrl::new(include_str!("worker.min.js"));
|
||||||
|
static WORKER: Worker = URL.with(|url| Worker::new(&url.0)).expect("`new Worker()` is not expected to fail with a local script");
|
||||||
|
}
|
||||||
|
|
||||||
|
let channel = MessageChannel::new().unwrap();
|
||||||
|
let closure = Closure::new(f);
|
||||||
|
let port_1 = channel.port1();
|
||||||
|
port_1.set_onmessage(Some(closure.as_ref().unchecked_ref()));
|
||||||
|
port_1.start();
|
||||||
|
|
||||||
|
// `Duration::as_millis()` always rounds down (because of truncation), we want to round
|
||||||
|
// up instead. This makes sure that the we never wake up **before** the given time.
|
||||||
|
let duration = duration
|
||||||
|
.as_secs()
|
||||||
|
.try_into()
|
||||||
|
.ok()
|
||||||
|
.and_then(|secs: u32| secs.checked_mul(1000))
|
||||||
|
.and_then(|secs| secs.checked_add(duration.subsec_micros().div_ceil(1000)))
|
||||||
|
.unwrap_or(u32::MAX);
|
||||||
|
|
||||||
|
WORKER
|
||||||
|
.with(|worker| {
|
||||||
|
let port_2 = channel.port2();
|
||||||
|
worker.post_message_with_transfer(
|
||||||
|
&Array::of2(&port_2, &duration.into()),
|
||||||
|
&Array::of1(&port_2).into(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.expect("`Worker.postMessage()` is not expected to fail");
|
||||||
|
|
||||||
|
Schedule { _closure: closure, inner: Inner::Worker(port_1) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Schedule {
|
impl Drop for Schedule {
|
||||||
|
|
@ -167,6 +218,10 @@ impl Drop for Schedule {
|
||||||
port.close();
|
port.close();
|
||||||
port.set_onmessage(None);
|
port.set_onmessage(None);
|
||||||
},
|
},
|
||||||
|
Inner::Worker(port) => {
|
||||||
|
port.close();
|
||||||
|
port.set_onmessage(None);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,6 +269,29 @@ fn has_idle_callback_support(window: &web_sys::Window) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ScriptUrl(String);
|
||||||
|
|
||||||
|
impl ScriptUrl {
|
||||||
|
fn new(script: &str) -> Self {
|
||||||
|
let sequence = Array::of1(&script.into());
|
||||||
|
let mut property = BlobPropertyBag::new();
|
||||||
|
property.type_("text/javascript");
|
||||||
|
let blob = Blob::new_with_str_sequence_and_options(&sequence, &property)
|
||||||
|
.expect("`new Blob()` should never throw");
|
||||||
|
|
||||||
|
let url = Url::create_object_url_with_blob(&blob)
|
||||||
|
.expect("`URL.createObjectURL()` should never throw");
|
||||||
|
|
||||||
|
Self(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ScriptUrl {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
Url::revoke_object_url(&self.0).expect("`URL.revokeObjectURL()` should never throw");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
type WindowSupportExt;
|
type WindowSupportExt;
|
||||||
|
|
|
||||||
10
src/platform_impl/web/web_sys/worker.js
Normal file
10
src/platform_impl/web/web_sys/worker.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
onmessage = event => {
|
||||||
|
const [port, timeout] = event.data
|
||||||
|
const f = () => port.postMessage(undefined)
|
||||||
|
|
||||||
|
if ('scheduler' in this) {
|
||||||
|
scheduler.postTask(f, { delay: timeout })
|
||||||
|
} else {
|
||||||
|
setTimeout(f, timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/platform_impl/web/web_sys/worker.min.js
vendored
Normal file
1
src/platform_impl/web/web_sys/worker.min.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
onmessage=e=>{let[s,t]=e.data,a=()=>s.postMessage(void 0);"scheduler"in this?scheduler.postTask(a,{delay:t}):setTimeout(a,t)};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue