Dart Async & Await

Handle asynchronous operations with ease

⏰ What is Async & Await?

Async and await help you write asynchronous code that looks like synchronous code. They make it easy to handle operations that take time, like network requests or file operations.


Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 2));
  return 'Data loaded!';
}

void main() async {
  print('Loading...');
  String result = await fetchData();
  print(result);
}
                                    

Output:

Loading...

(2 seconds later)

Data loaded!

Async Programming Concepts

🔄

Async Functions

Functions that return Future objects

Future<String> getData() async {
  return 'Hello';
}

Await Keyword

Wait for async operations to complete

String result = await getData();
print(result);
📦

Future Objects

Represent values available in the future

Future<int> calculation = 
  Future.value(42);
🛡️

Error Handling

Handle async errors with try-catch

try {
  await riskyOperation();
} catch (e) {
  print('Error: $e');
}

🔹 Basic Async Function

Create and use async functions:

// Simple async function
Future<String> greetUser(String name) async {
  // Simulate some delay (like network request)
  await Future.delayed(Duration(seconds: 1));
  return 'Hello, $name!';
}

// Function that performs multiple async operations
Future<void> processUser(String name) async {
  print('Processing user: $name');
  
  // Wait for greeting
  String greeting = await greetUser(name);
  print(greeting);
  
  // Simulate another async operation
  await Future.delayed(Duration(milliseconds: 500));
  print('User $name processed successfully!');
}

void main() async {
  print('Starting...');
  
  await processUser('Alice');
  await processUser('Bob');
  
  print('All done!');
}

Output:

Starting...

Processing user: Alice

Hello, Alice!

User Alice processed successfully!

Processing user: Bob

Hello, Bob!

User Bob processed successfully!

All done!

🔹 Parallel Async Operations

Run multiple async operations simultaneously:

Future<String> fetchUserData(String userId) async {
  await Future.delayed(Duration(seconds: 1));
  return 'User data for $userId';
}

Future<String> fetchUserPosts(String userId) async {
  await Future.delayed(Duration(seconds: 2));
  return 'Posts for $userId';
}

Future<String> fetchUserFriends(String userId) async {
  await Future.delayed(Duration(seconds: 1));
  return 'Friends for $userId';
}

void main() async {
  String userId = 'user123';
  
  print('Sequential execution:');
  var start = DateTime.now();
  
  // Sequential - takes about 4 seconds total
  String userData = await fetchUserData(userId);
  String userPosts = await fetchUserPosts(userId);
  String userFriends = await fetchUserFriends(userId);
  
  var sequential = DateTime.now().difference(start);
  print('Sequential took: ${sequential.inMilliseconds}ms');
  
  print('\nParallel execution:');
  start = DateTime.now();
  
  // Parallel - takes about 2 seconds (longest operation)
  List<String> results = await Future.wait([
    fetchUserData(userId),
    fetchUserPosts(userId),
    fetchUserFriends(userId),
  ]);
  
  var parallel = DateTime.now().difference(start);
  print('Parallel took: ${parallel.inMilliseconds}ms');
  print('Results: $results');
}

Output:

Sequential execution:

Sequential took: ~4000ms

Parallel execution:

Parallel took: ~2000ms

Results: [User data for user123, Posts for user123, Friends for user123]

🔹 Error Handling in Async Code

Handle errors in asynchronous operations:

Future<String> fetchDataFromServer(String endpoint) async {
  await Future.delayed(Duration(seconds: 1));
  
  // Simulate different scenarios
  if (endpoint == 'error') {
    throw Exception('Server error occurred');
  } else if (endpoint == 'timeout') {
    throw TimeoutException('Request timed out', Duration(seconds: 5));
  }
  
  return 'Data from $endpoint';
}

Future<void> handleDataFetching() async {
  List<String> endpoints = ['users', 'error', 'posts', 'timeout'];
  
  for (String endpoint in endpoints) {
    try {
      print('Fetching from $endpoint...');
      String data = await fetchDataFromServer(endpoint);
      print('Success: $data');
      
    } on TimeoutException catch (e) {
      print('Timeout error: ${e.message}');
    } catch (e) {
      print('General error: $e');
    } finally {
      print('Finished processing $endpoint\n');
    }
  }
}

void main() async {
  await handleDataFetching();
  print('All requests completed!');
}

Output:

Fetching from users...

Success: Data from users

Finished processing users

Fetching from error...

General error: Exception: Server error occurred

Finished processing error

Fetching from posts...

Success: Data from posts

Finished processing posts

Fetching from timeout...

Timeout error: Request timed out

Finished processing timeout

All requests completed!

🔹 Async with Real-World Example

A practical example simulating a login process:

class AuthService {
  Future<bool> validateCredentials(String username, String password) async {
    print('Validating credentials...');
    await Future.delayed(Duration(seconds: 1));
    
    // Simple validation
    return username == 'admin' && password == 'password123';
  }
  
  Future<String> fetchUserProfile(String username) async {
    print('Fetching user profile...');
    await Future.delayed(Duration(milliseconds: 800));
    return 'Profile data for $username';
  }
  
  Future<List<String>> fetchUserPermissions(String username) async {
    print('Fetching permissions...');
    await Future.delayed(Duration(milliseconds: 600));
    return ['read', 'write', 'admin'];
  }
}

Future<void> loginUser(String username, String password) async {
  var auth = AuthService();
  
  try {
    print('Starting login process for $username...');
    
    // Step 1: Validate credentials
    bool isValid = await auth.validateCredentials(username, password);
    
    if (!isValid) {
      print('Login failed: Invalid credentials');
      return;
    }
    
    print('Credentials valid! Loading user data...');
    
    // Step 2: Fetch user data in parallel
    var results = await Future.wait([
      auth.fetchUserProfile(username),
      auth.fetchUserPermissions(username),
    ]);
    
    String profile = results[0];
    List<String> permissions = results[1] as List<String>;
    
    print('Login successful!');
    print('Profile: $profile');
    print('Permissions: $permissions');
    
  } catch (e) {
    print('Login error: $e');
  }
}

void main() async {
  await loginUser('admin', 'password123');
  print('---');
  await loginUser('user', 'wrongpass');
}

Output:

Starting login process for admin...

Validating credentials...

Credentials valid! Loading user data...

Fetching user profile...

Fetching permissions...

Login successful!

Profile: Profile data for admin

Permissions: [read, write, admin]

---

Starting login process for user...

Validating credentials...

Login failed: Invalid credentials

🧠 Test Your Knowledge

What keyword do you use to wait for an async operation to complete?