What is Asynchronous Programming?
Asynchronous programming allows your program to perform time‑consuming tasks (like network requests, file I/O, or database queries) without blocking the main thread. Instead of waiting for the task to complete, the program continues executing other code and gets notified when the task is done. This is essential for building responsive applications, especially in Flutter.
Futures: The Building Block
A Future represents a potential value or error that will be available at some time in the future. You can think of it as a promise that a value will be delivered later. Dart provides two ways to work with Futures: using the .then() callback or using async/await. The latter is more readable and recommended.
The async and await Keywords
The async keyword marks a function as asynchronous. It tells Dart that the function will return a Future. Inside an async function, you can use await to pause execution until a Future completes, without blocking the thread. The await expression returns the value of the Future (or throws an error if the Future completes with an error).
Note that main() itself can be async. This is common in command‑line apps and Flutter's main() can also be async if needed.
Error Handling with try/catch
When you use await, errors from the Future are thrown as exceptions. You can catch them using a regular try/catch block, just like synchronous code.
Multiple Awaits and Sequential Execution
When you need to perform several asynchronous tasks one after another, you can simply await each one in order. They will run sequentially.
Running Futures in Parallel: Future.wait
If you have multiple independent asynchronous tasks, you can run them concurrently using Future.wait. It takes a list of Futures and returns a Future that completes when all of them are done, yielding a list of results.
Async* and Streams (Brief Overview)
For multiple values over time, Dart uses Stream. An async* function returns a Stream and uses yield to emit values. This is beyond the scope of async/await but is another important asynchronous concept.
Best Practices
- Always mark functions that use
awaitwithasync.
- Always mark functions that use
- Prefer
async/awaitover.then()for readability.
- Prefer
- Use
try/catchto handle errors in async functions.
- Use
- Use
Future.waitfor concurrent independent tasks.
- Use
- Be careful with long‑running synchronous code inside an async function; it still blocks the event loop.
Complete Example
Key Takeaways
asyncmarks a function that returns aFuture.
awaitpauses the function until a Future completes.
- Use
try/catchto handle errors in async code.
- Use
Future.waitruns multiple Futures concurrently.
- Async/await makes asynchronous code look and behave like synchronous code, improving readability.