Reputation: 3118
Re-building setInterval
in JS:
pub async fn set_interval<T, F>(interval: Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: Future + Send,
{
let forever = task::spawn(async move {
let mut interval = time::interval(interval);
loop {
interval.tick().await;
do_something().await;
}
});
forever.await;
}
This works, but I want it to be .await
able until the first execution ends.
I.e. Instead of doing:
do_something().await
set_interval(Duration::from_secs(1), do_something)
I want to:
set_interval(Duration::from_secs(1), do_something).await
Note that this is different behaviour from above in that it runs the do_something
task immediately, but it's intended.
My solution:
pub async fn set_interval<T, F>(interval: Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: Future + Send,
{
do_something().await;
task::spawn(async move {
let forever = task::spawn(async move {
let mut interval = time::interval(interval);
loop {
interval.tick().await;
do_something().await;
}
});
forever.await;
});
}
This works, but I have some doubts
task::spawn
twice here? Any way it can be done only once?task::spawn
as soon as the function ends? Will it keep getting run indefinitely, even though it's not tracked anymore, just fired and forgotten?Upvotes: 0
Views: 1205
Reputation: 8534
To answer your two questions:
forever.await
;The following seems to work:
pub async fn set_interval<T, F>(interval: std::time::Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: std::future::Future + Send,
{
// The interval time alignment is decided at construction time.
// For all calls to be evenly spaced, the interval must be constructed first.
let mut interval = tokio::time::interval(interval);
// The first tick happens without delay.
// Whether to tick before the first do_something or after doesn't matter.
interval.tick().await;
do_something().await;
tokio::task::spawn(async move {
loop {
interval.tick().await;
do_something().await;
}
});
}
Upvotes: 4