Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tracking] browser WASM support #220

Open
2 of 5 tasks
yoshuawuyts opened this issue Sep 19, 2019 · 19 comments
Open
2 of 5 tasks

[tracking] browser WASM support #220

yoshuawuyts opened this issue Sep 19, 2019 · 19 comments
Labels
api design Open design questions enhancement New feature or request

Comments

@yoshuawuyts
Copy link
Contributor

yoshuawuyts commented Sep 19, 2019

It'd be cool if async-std worked in the browser out of the box. Not everything can be supported, but we can support a smaller subset.

Tasks

  • no longer fail compilation under the --target wasm32-unknown-unknown target
  • make task::spawn work (use wasm_bindgen_futures::spawn_local)
  • expose stream
  • expose task::sleep
  • patch async-attributes to allow async fn main to work

References

@yoshuawuyts yoshuawuyts added enhancement New feature or request api design Open design questions labels Sep 19, 2019
@ghost
Copy link

ghost commented Sep 19, 2019

Should we introduce async_std::os::wasm::task::spawn_local that calls wasm_bindgen_futures::spawn_local?

Or should we perhaps have async_std::task::spawn_local that doesn't have the Send bound and works on all platforms? On wasm it would call wasm_bindgen_futures::spawn_local and on other platforms it could do something else.

What if every thread was technically a worker thread onto which local tasks can be spawned? We could have thread-local task queues into which spawn_local pushes tasks. Regular worker threads would run tasks both from their regular queues and from those local queues, while other threads outside the runtime would run tasks from their local queues only when an invocation of async_std::task::block_on is idle.

Just some ideas...

@tomaka
Copy link

tomaka commented Sep 19, 2019

(EDIT: I said something wrong regarding wasm-bindgen-futures, they recently upgraded to stable futures)

One challenge is that futures_timer will panic at runtime, because it calls std::time::Instant::now(), which panics in WASM.

@ghost
Copy link

ghost commented Sep 19, 2019

Can we replace futures-timer with something else on wasm? Can we perhaps spawn a JS promise that completes after some number of seconds and then await that future?

Also, since Instant::now() panics on wasm, is it possible to get the current time on by invoking a JS function?

@tomaka
Copy link

tomaka commented Sep 19, 2019

Can we replace futures-timer with something else on wasm? Can we perhaps spawn a JS promise that completes after some number of seconds and then await that future?

Yes, that should be possible. Example (with old futures): https://github.com/tomaka/wasm-timer/blob/fd76bd42824fcee5232959df3f8a15cb58e33c46/src/wasm.rs#L209-L278

Also, since Instant::now() panics on wasm, is it possible to get the current time on by invoking a JS function?

Yes. one can use performance.now().
Example: https://github.com/tomaka/wasm-timer/blob/366b8003189487d1468dd1b65be8523fb4ae4245/src/wasm.rs#L57-L64

The problem is that it is clearly a hack to assume that wasm32-unknown-unknown means "browser". As its name says, it's "unknown". I don't have a solution to that.

@yoshuawuyts
Copy link
Contributor Author

What if every thread was technically a worker thread onto which local tasks can be spawned? We could have thread-local task queues into which spawn_local pushes tasks.

@davidbarsky mentioned something like this earlier; that's very interesting!


@tomaka I was thinking of sidestepping futures-timer entirely and creating async bindings to the timing facilities directly. It seems like that would help with keeping bundle sizes down also.

Perhaps it would actually make sense to add a time submodule for WASM specifically so things like time::Instant::now() actually works? I think having that would actually be really valuable, and we could probably lean heavily on the work you've already done.

The problem is that it is clearly a hack to assume that wasm32-unknown-unknown means "browser".

I've talked with the wasm team about this, and they recommended to do feature detection for wasm-bindgen which is always passed (I believe). Afaik that should be the most reliable solution right now.

@tomaka
Copy link

tomaka commented Sep 20, 2019

they recommended to do feature detection for wasm-bindgen which is always passed (I believe)

I don't understand what you mean by that?

@yoshuawuyts
Copy link
Contributor Author

@tomaka feature flag it as:

#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]

as recommended by the wasm team. Not 100%, but better than just target_arch (:

@tomaka
Copy link

tomaka commented Sep 20, 2019

So we would need three code paths:

  • The regular one (Unix, Windows)
  • The one with wasm32 + wasm-bindgen that invokes JS functions.
  • The one with only wasm32 that returns an error/panics all the time?

@yoshuawuyts
Copy link
Contributor Author

@tomaka yeah that's about it for now. Eventually we may want to support WASI too, but async support doesn't exist yet. We should engage the team more closely on this though; it's been a while since we last talked about it in-depth.

@kellytk
Copy link

kellytk commented Oct 3, 2019

Related Tokio issue.

@ghost
Copy link

ghost commented Oct 7, 2019

Related project: https://github.com/richardanaya/asynctimer

@dignifiedquire
Copy link
Member

The core work of this happened in #757 and will be available in 1.6

@GopherJ
Copy link

GopherJ commented May 11, 2020

@yoshuawuyts You have checked task::spawn, any idea on why it cannot be found when I run:

cargo check \             
--target  wasm32-unknown-unknown

It shows:

error[E0425]: cannot find function `spawn` in module `task`
  --> src/effector.rs:31:25
   |
31 |         let fut = task::spawn(async move {
   |                         ^^^^^ not found in `task`
   |
help: consider importing this function
   |
1  | use std::thread::spawn;
   |

error: aborting due to previous error

For more information about this error, try `rustc --explain E0425`.
error: could not compile `casbin`.

To learn more, run the command again with --verbose.

EDIT:

change to spawn_local works

@sergeyt
Copy link

sergeyt commented Jun 19, 2020

i've got this error when running cargo check --target wasm32-unknown-unknown:

failed to resolve: use of undeclared type or module `futures_timer`
  --> /Users/admin/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.6.2/src/utils.rs:84:29
   |
84 |     pub(crate) struct Timer(futures_timer::Delay);
   |                             ^^^^^^^^^^^^^ use of undeclared type or module `futures_timer`

@dignifiedquire
Copy link
Member

@sergeyt which vesion was that?

@ghost
Copy link

ghost commented Jun 21, 2020

@dignifiedquire It says 1.6.2 :)

src/github.com-1ecc6299db9ec823/async-std-1.6.2/src/utils.rs:84:29

@dignifiedquire
Copy link
Member

reading is hard :(

@afilini
Copy link

afilini commented Jul 19, 2020

i've got this error when running cargo check --target wasm32-unknown-unknown:

failed to resolve: use of undeclared type or module `futures_timer`
  --> /Users/admin/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-1.6.2/src/utils.rs:84:29
   |
84 |     pub(crate) struct Timer(futures_timer::Delay);
   |                             ^^^^^^^^^^^^^ use of undeclared type or module `futures_timer`

I think you'll have to add the unstable feature to make this work

@ben-albrecht
Copy link

What are the next steps for this issue?

I am specifically interested in a WASM-friendly sleep. It looks like there is a working example of this from 3 years ago from the comment above:

https://github.com/richardanaya/asynctimer

Any progress since then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api design Open design questions enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

8 participants