-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improve ergonomics of async integration #4020
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
Comments
To clarify, with the callback you need to await the result of the call like this. The rest of the closure will only run when the await is finished: #[component]
pub fn SpinnerButton(
onclick: Callback<MouseEvent, Pin<Box<dyn Future<Output = ()>>>>,
running: Signal<bool>,
) -> Element {
rsx! {
button {
onclick: move |evt| async move {
running.set(true);
onclick(evt).await;
running.set(false);
}
}
}
}
The browser runtime is largely single threaded which means we cannot block the main thread without freezing the whole page. If this is implemented, we would need to return a future from the maybe-future event handler call so you could await it when you call the event handler like in the code snippet above |
Thank you for explaining the issue, I think I see the problem more clearly now. I'm not sure how the internal mechanics work. It certainly seems like async tasks are supported, but that's all on a single thread. Is that correct so far? Hm, I was wondering if there was some way to make the hypothetical waiting-for-completion In pseudo-code, is it possible to call a function that runs "other things", until completion. Kind of like this rough sketch: impl Event {
pub fn call(&self) -> {
magical_async_reactor_core.run_stuff_until_done(self.future);
}
} I know that's a rough sketch, but do you see what I mean? I'll admit, I have no idea if that's possible, or feasible. It's very hand-wavy, but it would make for an easy interface for programmers. Alternatively, would it make since for event handlers to always be async? That would also make integrations smoother. But in the end, your suggestion for a workaround is pretty solid. It's a bit verbose, but very manageable with a type alias. |
Feature Request
This is a spin-off from #4011 ("Async closure for "onclick": spawns into the aether").
Related issue: #3481
When interfacing with a rest api, and targeting web, there's really no other choice than using an async http client. This means lots of async integration in event handlers.
In general, this can work:
However, it's not that ergonomic to use:
1. The "magic" async support works by returning a future from the event handler
This means there's no way to use an async block in the middle of the event handler. The entire "bottom half" (or the whole) of the event handler must be async.
2. There's (seemingly?) no way to .await the async block
This makes it extra difficult to make things happen in a certain order.
For example, I tried to make a button component that displays a spinner while the
.onclick
is running. Conceptually, something like this:This seems reasonable, no?
Well, if
onclick
is given as anasync
move block, it's wrapped in something that causes it to be spawned, but not awaited in a blocking-like way. The result is that.call()
exits immediately, and so theSpinnerButton
concept appears broken.This is pretty surprising, and I haven't been able to find a workaround of any kind.
Suggestion
In #4011, @ealmloff had this comment:
The workaround is certainly a neat idea, but it does come with some problems:
I think there's a design problem with the way async closures are handled right now.
In other words:
Should wait until the closure is done running, no matter if it's sync or async.
I'm not sure how exactly to implement this, but that would solve this entire issue.
Anyone who explicitly wants to spawn a background task, can already do so with the
spawn()
helper.I can't really see any downside to the blocking behavior, but there's plenty of advantages.
Thoughts?
The text was updated successfully, but these errors were encountered: