Async Commands in Tauri: Background Tasks with Progress Events | Rust + React
Video: Async Commands in Tauri: Background Tasks with Progress Events | Rust + React by Taught by Celeste AI - AI Coding Coach
Watch full page →Async Commands in Tauri: Background Tasks with Progress Events
Running long operations directly in Tauri can freeze your UI, but async commands let you keep your app responsive by running tasks in the background. This example shows how to create an async Rust command that emits progress events to a React frontend, enabling a live progress bar that updates smoothly during the operation.
Code
use serde::Serialize;
use std::time::Duration;
use tauri::{AppHandle, Manager};
use tokio::time::sleep;
#[derive(Clone, Serialize)]
struct ProgressPayload {
progress: u32,
message: String,
is_complete: bool,
}
// Async Tauri command that simulates a long-running task with progress updates
#[tauri::command]
async fn process_task(app: AppHandle, total_steps: u32) -> Result {
for step in 1..=total_steps {
// Simulate work with a non-blocking 100ms delay
sleep(Duration::from_millis(100)).await;
// Calculate progress percentage
let progress = (step * 100) / total_steps;
// Create progress payload
let payload = ProgressPayload {
progress,
message: format!("Step {} of {}", step, total_steps),
is_complete: false,
};
// Emit progress event to frontend
app.emit_all("progress-event", payload).map_err(|e| e.to_string())?;
}
// Emit final complete event
let complete_payload = ProgressPayload {
progress: 100,
message: "Task complete!".into(),
is_complete: true,
};
app.emit_all("progress-event", complete_payload).map_err(|e| e.to_string())?;
Ok("Processing finished successfully".into())
}
// In your main.rs or lib.rs, register the command:
// tauri::Builder::default()
// .invoke_handler(tauri::generate_handler![process_task])
// .run(tauri::generate_context!())
// .expect("error while running tauri application");
Key Points
- Marking a Tauri command as
async fnruns it on Tokio's thread pool, preventing UI blocking. - Use
tokio::time::sleep().awaitto simulate or perform non-blocking delays inside async tasks. - Emit progress updates from Rust to the frontend using
app.emit_all("event-name", payload)with serializable data. - Frontend can listen to these events to update UI elements like progress bars in real time.
- Always register your async commands with
invoke_handlerso they are callable from the frontend.