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

wasm-bindgen-futures: use queueMicrotask for next tick runs (#3203) #3611

Merged
merged 3 commits into from
Sep 15, 2023

Conversation

flumm
Copy link
Contributor

@flumm flumm commented Sep 13, 2023

but use catch to wrap it in a Result to be able to fall back to the previous Promsise.then variant.

since this is my first pull request here, i hope the code is ok this way, but a few questions remain:

  • i simply imported queueMicrotask in global scope, since this should work for both non workers (window) and workers AFAICT
  • i tried to run the tests mentioned here: https://rustwasm.github.io/docs/wasm-bindgen/contributing/testing.html but
    the first one failed (regardless of my changes) and cargo test -p ui-tests also did not work (the remaining tests worked, as well as the ones directly in wasm-bindgen-futures
  • i tested Can't catch async Wasm traps in JS #2392 with this, and this now seems to work
  • is the way i fall back to the old implementation ok? i couldn't find a way to import bindings 'optionally' or test during runtime if a function exists?
  • also is embedding such functionality from javascript directly ok? orwould it better be to add that to web-sys/js-sys first and use that?

Fixes #2392.

@daxpedda
Copy link
Collaborator

  • i simply imported queueMicrotask in global scope, since this should work for both non workers (window) and workers AFAICT

That's fine.

The contributor experience is awful in this regard and should be improved/fixed.

Thanks, I added it to the OP.

  • is the way i fall back to the old implementation ok? i couldn't find a way to import bindings 'optionally' or test during runtime if a function exists?

We could use OnceLock, but v1.70 seems high right now and we don't have a proper MSRV policy. Alternatively we could use once_cell, but that would be adding another dependency.

@Liamolucko what do you think of adding once_cell to the dependency tree of wasm-bindgen-futures, personally I'm fine with it.

  • also is embedding such functionality from javascript directly ok? orwould it better be to add that to web-sys/js-sys first and use that?

Probably, but our story for WindowOrGlobalWorker is pretty weak, so I think it's better to leave it like that.

Copy link
Collaborator

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like to figure out first how we could cache queueMicrotask availability first, but otherwise LGTM.

Would you mind adding a note to the changelog as well?

@daxpedda daxpedda self-assigned this Sep 14, 2023
@daxpedda daxpedda added the waiting for author Waiting for author to respond label Sep 14, 2023
@Liamolucko
Copy link
Collaborator

The contributor experience is awful in this regard and should be improved/fixed.

The specific two problems there are that the main wasm32-unknown-unknown tests need you to to specify WASM_BINDGEN_SPLIT_LINKED_MODULES=1, as there's one test that relies on --split-linked-modules being enabled, and that the UI tests need to be run with a specific version of Rust since error messages change between versions (currently v1.69.0).

The WASM_BINDGEN_SPLIT_LINKED_MODULES one is actually quite annoying; it might be a good idea to add that to .cargo/config so that you don't have to specify it every time.

But yeah, those should both be either documented or fixed.

@Liamolucko what do you think of adding once_cell to the dependency tree of wasm-bindgen-futures, personally I'm fine with it.

I'm fine with that too.

@flumm
Copy link
Contributor Author

flumm commented Sep 15, 2023

We could use OnceLock, but v1.70 seems high right now and we don't have a proper MSRV policy. Alternatively we could use once_cell, but that would be adding another dependency.

@Liamolucko what do you think of adding once_cell to the dependency tree of wasm-bindgen-futures, personally I'm fine with it.

maybe i'm missing part of the puzzle, but wouldn't it be enough to try executing it once (with e.g. an empty closure) in new() and save the result of .is_err() of that into the queue as struct member?

then we could do:

if <...> && (self.needs_fallback || queueMicrotask(...)) {

?
then it's a simple boolean check without OnceLock or once_cell ?
or how did you mean to use them?

Would like to figure out first how we could cache queueMicrotask availability first, but otherwise LGTM.

Would you mind adding a note to the changelog as well?

sure no problem, do you prefer i push another commit, or should i force push my branch?
(what is preferred in general? AFAIR github mangles reviews when force pushing, but adding commits can be cumbersome when a pull request has many changes? Sorry for the stupid questions, but I'm used to
mailing list workflow, and seldom do github pull requests)

The specific two problems there are that the main wasm32-unknown-unknown tests need you to to specify WASM_BINDGEN_SPLIT_LINKED_MODULES=1, as there's one test that relies on --split-linked-modules being enabled, and that the UI tests need to be run with a specific version of Rust since error messages change between versions (currently v1.69.0).

The WASM_BINDGEN_SPLIT_LINKED_MODULES one is actually quite annoying; it might be a good idea to add that to .cargo/config so that you don't have to specify it every time.

But yeah, those should both be either documented or fixed.

thanks that worked for the first test, but running cargo test -p ui-tests results here (rustc 1.69.0) with

error: package ID specification ui-tests did not match any packages

@daxpedda
Copy link
Collaborator

daxpedda commented Sep 15, 2023

We could use OnceLock, but v1.70 seems high right now and we don't have a proper MSRV policy. Alternatively we could use once_cell, but that would be adding another dependency.
@Liamolucko what do you think of adding once_cell to the dependency tree of wasm-bindgen-futures, personally I'm fine with it.

maybe i'm missing part of the puzzle, but wouldn't it be enough to try executing it once (with e.g. an empty closure) in new() and save the result of .is_err() of that into the queue as struct member?

then we could do:

if <...> && (self.needs_fallback || queueMicrotask(...)) {

? then it's a simple boolean check without OnceLock or once_cell ?
or how did you mean to use them?

That would be better indeed!

Instead of calling queueMicrotask() with an empty closure, you should probably be able to do:

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(getter)]
    fn queueMicrotask() -> JsValue;
}

Which returns undefined if not present. Never tried it with global, but should work just fine. Then we should also be able to remove the catch from the actualy queueMicrotask() bindings, which AFAIK can't actually throw.

thanks that worked for the first test, but running cargo test -p ui-tests results here (rustc 1.69.0) with

I'm assuming this needs to be called from inside some package.
Documentation has to be improved in this regard.

@flumm
Copy link
Contributor Author

flumm commented Sep 15, 2023

That would be better indeed!

Instead of calling queueMicrotask() with an empty closure, you should probably be able to do:

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(getter)]
    fn queueMicrotask() -> JsValue;
}

Which returns undefined if not present. Never tried it with global, but should work just fine. Then we should also be able to remove the catch from the actualy queueMicrotask() bindings, which AFAIK can't actually throw.

it seems that does not work, AFAICS the 'getter' property in the macro is ignored for non struct members

possible alternatives i saw were using the Window::get but i guess that does not work for workers anymore (and i couldn't find an alternative for workers...)

or using something like:

#[wasm_bindgen(inline_js = "export function queueMicrotaskExists() { return typeof queueMicrotask === 'function' }")]
extern "C" {
    fn queueMicrotaskExists() -> bool;
}

but that seems also overly complicated...

(also you did not answer my question about the pull request update, should i force push or add commits?)

Thanks!

@daxpedda
Copy link
Collaborator

possible alternatives i saw were using the Window::get but i guess that does not work for workers anymore (and i couldn't find an alternative for workers...)

We would want to avoid that because of the overhead from the string.
The solution is probably something like this:

#[wasm_bindgen]
extern "C" {
	type Global;

	#[wasm_bindgen(method, getter, js_name = queueMicrotask)]
	fn hasQueueMicrotask(this: &Global) -> JsValue;
}

let global: Global = js_sys::global().unchecked_into();
let has_queue_microtask = global.hasQueueMicrotask();

(also you did not answer my question about the pull request update, should i force push or add commits?)

Apologies!
The PR will be squashed before merging anyway, so you can do w/e you like. Personally I only need a "nice" commit history if it makes reviewing easier, which for such a small PR is irrelevant to me.

@flumm
Copy link
Contributor Author

flumm commented Sep 15, 2023

ah thanks, the 'Global' part was what i was missing, big thanks :)

i'll update my branch shortly

…wasm#3203)

but use the old `Promise.then` mechanism as a fallback. Cache the
existance of `queueMicrotask` in the queue instance.

Signed-off-by: Dominik Csapak <[email protected]>
@flumm flumm force-pushed the use-queueMicrotask branch from 0d54602 to 44126a3 Compare September 15, 2023 12:36
CHANGELOG.md Outdated Show resolved Hide resolved
crates/futures/src/queue.rs Outdated Show resolved Hide resolved
only the pull request is relevant

Signed-off-by: Dominik Csapak <[email protected]>
@flumm flumm requested a review from daxpedda September 15, 2023 14:17
Copy link
Collaborator

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@daxpedda daxpedda merged commit d41202a into rustwasm:main Sep 15, 2023
25 checks passed
@daxpedda daxpedda removed the waiting for author Waiting for author to respond label Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't catch async Wasm traps in JS
3 participants