`winit::TabLeft`/`Event::Suspended` doesn't function as intended on WASM
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## Bevy version
0.13
## What went wrong
JavaScript is an interpreted language, and the browser will essentially suspend code execution completely if the tab is hidden. Bevy's systems are tied to `requestAnimationFrame`, which is also completely paused when the user is tabbed away from the window.
In other words: On wasm, the main thread gets suspended when it is hidden (e.g. when the user switches tabs). This means that the app.update() function will not be called, because bevy's scheduler only runs app.update() when the browser's `requestAnimationFrame` is called (and that happens only when the tab is visible).
What problem does this cause?
- No systems will execute whilst the tab is inactive. This means networking crates will disconnect easily (no communications being sent while alt-tabbed).
- Networking crates that don't disconnect may experience buffer overflows for bounded protocols, as they will process hundreds of missed packets all at once. This could result in dropped packets.
There's a *very* long discussion on how this problem affects lightyear [available here](https://github.com/cBournhonesque/lightyear/issues/144). We eventually come to a solution, which I'll propose below.
## The part about `winit::TabLeft`
So yeah, there is technically events like `Event::Suspended` in winit that are supposed to fire when the tab gets left. However, as aforementioned, no code executes when the tab is hidden. As a result, this event is handled only when you *return* to the tab!
< user leaves tab >
... 30 seconds
< user goes back to the tab >
--> new event: `Event::Suspended`
--> new event: `Event::Resumed`
_And what use is that?_ It's delivering no value currently. I'd call this a bug.
## The solution
A solution, credited to @Nul-led , is to add a very small plugin (~10 lines of code) to spawn a web worker which sends a message every 1 second (configurable time). A callback is added to the web browser's DOM events to execute the main schedule exactly 1 time.
The code can be seen here: https://github.com/cBournhonesque/lightyear/pull/371/files#diff-5ec95d0ed493b4b63bba9ae693c990e6e1612d2fbe6309df678bf21fb75fbc1b
## What I want
Selfishly, I want to see this in bevy. It's a very small amount of code but could be massively beneficial to many crates who want to keep a continuous run in the background when the tab is inactive.
Specifically, I think this should be a
```rust
pub struct WebExecutionPlugin {
callback_ms: f32 // default = 250.0 ms
}
```
that can be added to any application.
Furthermore, it would be nice to have a
```rust
#[derive(States)]
pub enum WindowFocusState {
Inactive,
Active,
}
```
that changes, depending on whether the window or tab is visible.
Contributor guide
Assessment
This issue has not been assessed yet.