Dart Async
Asynchronous programming is one of the most core capabilities in modern application development.
Whether it's network requests, file I/O, or database operations, all require asynchronous processing to avoid blocking the main thread.
This chapter introduces the concept of Future, async/await syntax, and how to handle asynchronous errors.
* * *
## Why Asynchronous Programming is Needed
First, understand the difference between synchronous and asynchronous.
Synchronous code executes line by line in order, and the next line won't start until the previous line completes.
If an operation needs to wait (such as a network request), the entire program will freeze.
## Example
Compare the execution effects of synchronous and asynchronous code:
// Simulate a time-consuming operation
String fetchDataSync(){
// Synchronous code: assume this takes 2 seconds to wait
// During these 2 seconds, the entire program cannot do anything
sleep(Duration(seconds:2));// Blocking wait
return'Data fetched';
}
// Asynchronous version: does not block the main thread
Future fetchDataAsync() async {
// Asynchronous wait: during these 2 seconds, the program can continue executing other tasks
await Future.delayed(Duration(seconds:2));
return'Data fetched';
}
void main() async {
print('Start synchronous data fetch...');
var syncResult = fetchDataSync();
print('Synchronous result: $syncResult');
print('(Note: program was blocked during sync)');
print('
Start asynchronous data fetch...');
print('After initiating request, program continues executing other tasks...');
var asyncResult = await fetchDataAsync();
print('Asynchronous result: $asyncResult');
print('(Program was not blocked during async)');
}
Start synchronous data fetch...Synchronous result: Data fetched(Note: program was blocked during sync)Start asynchronous data fetch...After initiating request, program continues executing other tasks...Asynchronous result: Data fetched(Program was not blocked during async)
> In Dart, all I/O operations (files, networks, databases) should use asynchronous methods. Synchronous I/O blocks the entire Isolate, which causes UI freezing in Flutter applications.
* * *
## Concept of Future
Future represents a value that "will complete at some point in the future".
It's like a promise: I don't have the result now, but I will definitely give you a value of type T in the future (or an error).
Future has three states:
| State | Description |
| --- | --- |
| Uncompleted | Asynchronous operation is still in progress |
| Completed with data | Operation succeeded, Future carries the result value |
| Completed with error | Operation failed, Future carries the error information |
## Example
Create and use Future:
void main(){
print('Program starts');
// Create a Future
Future future = Future((){
// This function will execute at some point in the future
return'TUTORIAL async result';
});
print('Future created, but not yet completed');
// Register callback: execute when Future completes
future.then((result){
print('Received result: $result');
});
print('Program continues...');
}
Program startsFuture created, but not yet completedProgram continues...Received result: TUTORIAL async result
Note the order of output: "Program continues" is printed first, then "Received result".
This shows that Future's callback is executed asynchronously and does not block subsequent code.
* * *
## async / await Syntax
async and await are the core syntax for handling asynchronous operations in Dart.
async marks a function as asynchronous, and await waits for a Future to complete and gets its result.
## Example
// async keyword marks function as asynchronous
// Asynchronous function's return type must be Future
Future fetchUserName(int id) async {
// await waits for Future to complete and gets its value
// During wait, current function pauses execution, but does not block other code
await Future.delayed(Duration(seconds:1));
return'User $id';
}
Future fetchUserAge(int id) async {
await Future.delayed(Duration(milliseconds:500));
return 20+ id;
}
// Execute multiple asynchronous operations sequentially
Future printUserInfo(int id) async {
print('Start fetching user info...');
// Wait one by one: get name first, then get age
var name = await fetchUserName(id);
print('Got name: $name');
var age = await fetchUserAge(id);
print('Got age: $age');
print('TUTORIAL user: $name, age: $age');
}
// Execute multiple asynchronous operations concurrently
Future printUserInfoParallel(int id) async {
print('Start fetching user info concurrently...');
// Initiate two requests at the same time, not waiting for each other
var nameFuture = fetchUserName(id);
var ageFuture = fetchUserAge(id);
// Wait for both requests to complete
var results = await Future.wait([nameFuture, ageFuture]);
var name = resultsas String;
var age = resultsas int;
print('TUTORIAL user (concurrent): $name, age: $age');
}
void main() async {
// Sequential execution (total time β 1s + 0.5s = 1.5s)
await printUserInfo(1);
print('---');
// Concurrent execution (total time β max(1s, 0.5s) = 1s)
await printUserInfoParallel(2);
}
Start fetching user info...Got name: User1Got age: 21 TUTORIAL user: User1, age: 21---Start fetching user info concurrently... TUTORIAL user (concurrent): User2, age: 22
> If multiple asynchronous operations have no dependencies between them, use Future.wait to let them execute concurrently instead of awaiting one by one. This can significantly improve performanceβthe total time equals the slowest operation, not the sum of all operations.
### Core Rules of async/await
| Rule | Description |
| --- | --- |
| async function returns Future | Even if function returns T, after async it will be automatically wrapped as Future |
| await can only be used in async functions | Regular functions cannot use await |
| await pauses current function | But does not block execution of other code |
| await gets Future's result | If Future has error, await will throw exception |
* * *
## then / catchError Chained Calls
Besides async/await, Dart also supports using then() and catchError() for chained calls.
This is the traditional Promise-stylesyntax.
## Example
// Function simulating network request
Future fetchData(String url){
return Future.delayed(Duration(seconds:1),(){
if(url.isEmpty){
throw Exception('URL cannot be empty');
}
return'Data from $url';
});
}
void main(){
print('Start request...');
// then / catchError chained calls
fetchData('https://example.com/api')
.then((data){
// Request successful
print('Got data: $data');
return'Processed: $data';// Return value will be passed to next then
})
.then((processed){
// Process return value from previous then
print(processed);
})
.catchError((error){
// Catch any error in the chain uniformly
print('Request error: $error');
})
.whenComplete((){
// Execute whether successful or failed (similar to finally)
print('Request ended (success
YouTip