Question #66EasyFlutter BasicsImportant

Flutter Difference between async , await , future ?

#flutter#async#future

Answer

Overview

async, await, and Future are Dart's tools for handling asynchronous operations (operations that take time, like network requests, file I/O, database queries).


Future

Definition: A

text
Future
represents a value that will be available at some point in the future. It's like a promise that a value will be provided later.

Example

dart
Future<String> fetchData() {
  return Future.delayed(
    Duration(seconds: 2),
    () => 'Data loaded',
  );
}

void main() {
  print('Start');
  fetchData(); // Returns immediately, doesn't block
  print('End'); // Prints before data loads

  // Output:
  // Start
  // End
  // (2 seconds later, data loads in background)
}

async

Definition: Marks a function as asynchronous, meaning it can perform async operations and return a

text
Future
.

Example

dart
Future<String> fetchData() async {
  // Simulate network delay
  await Future.delayed(Duration(seconds: 2));
  return 'Data loaded';
}

Key points:

  • Functions marked
    text
    async
    automatically return a
    text
    Future
  • Can use
    text
    await
    inside
    text
    async
    functions
  • Must return a
    text
    Future<T>
    or
    text
    Future<void>

await

Definition: Pauses execution of an

text
async
function until a
text
Future
completes, then returns the result.

Example

dart
Future<void> loadData() async {
  print('Loading...');

  String data = await fetchData(); // Waits for fetchData() to complete

  print('Loaded: $data');
}

void main() async {
  await loadData();
  print('Done');

  // Output:
  // Loading...
  // (waits 2 seconds)
  // Loaded: Data loaded
  // Done
}

Detailed Comparison

KeywordPurposeReturnsExample
FutureRepresents async resultFuture
text
Future<String> fetchData()
asyncMarks function as asyncFuture
text
Future<void> loadData() async { }
awaitWaits for Future to completeT (unwrapped value)
text
String data = await fetchData();

How They Work Together

Without async/await (Using .then())

dart
Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () => 'Data');
}

void main() {
  print('Start');

  fetchData().then((data) {
    print('Loaded: $data');
  }).catchError((error) {
    print('Error: $error');
  });

  print('End');

  // Output:
  // Start
  // End
  // (2 seconds later)
  // Loaded: Data
}

With async/await (Cleaner)

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

void main() async {
  print('Start');

  String data = await fetchData(); // Waits here
  print('Loaded: $data');

  print('End');

  // Output:
  // Start
  // (2 seconds later)
  // Loaded: Data
  // End
}

Real-World Examples

Example 1: API Call

dart
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<List<User>> fetchUsers() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/users'),
  );

  if (response.statusCode == 200) {
    final List<dynamic> data = jsonDecode(response.body);
    return data.map((json) => User.fromJson(json)).toList();
  } else {
    throw Exception('Failed to load users');
  }
}

// Usage
void main() async {
  try {
    List<User> users = await fetchUsers();
    print('Loaded ${users.length} users');
  } catch (e) {
    print('Error: $e');
  }
}

Example 2: Multiple Async Operations (Sequential)

dart
Future<void> loadUserData() async {
  print('Fetching user...');
  User user = await fetchUser(); // Wait for user

  print('Fetching user posts...');
  List<Post> posts = await fetchUserPosts(user.id); // Wait for posts

  print('User: ${user.name}, Posts: ${posts.length}');
}

Example 3: Multiple Async Operations (Parallel)

dart
Future<void> loadDashboard() async {
  print('Loading dashboard...');

  // Run both API calls in parallel
  final results = await Future.wait([
    fetchUser(),
    fetchPosts(),
    fetchComments(),
  ]);

  final user = results[0] as User;
  final posts = results[1] as List<Post>;
  final comments = results[2] as List<Comment>;

  print('Loaded user, ${posts.length} posts, ${comments.length} comments');
}

Example 4: Timeout

dart
Future<String> fetchDataWithTimeout() async {
  try {
    return await fetchData().timeout(Duration(seconds: 5));
  } on TimeoutException {
    return 'Request timed out';
  }
}

Error Handling

Using try-catch

dart
Future<void> loadData() async {
  try {
    String data = await fetchData();
    print('Success: $data');
  } catch (e) {
    print('Error: $e');
  } finally {
    print('Cleanup');
  }
}

Using .catchError()

dart
void loadData() {
  fetchData()
      .then((data) => print('Success: $data'))
      .catchError((error) => print('Error: $error'));
}

Flutter Example (Async in Widgets)

FutureBuilder

dart
class UserProfile extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: fetchUser(), // Async operation
      builder: (context, snapshot) {
        // Loading
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        }

        // Error
        if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        }

        // Success
        if (snapshot.hasData) {
          final user = snapshot.data!;
          return Text('User: ${user.name}');
        }

        return Text('No data');
      },
    );
  }
}

StatefulWidget with async

dart
class UserPage extends StatefulWidget {
  
  _UserPageState createState() => _UserPageState();
}

class _UserPageState extends State<UserPage> {
  User? _user;
  bool _isLoading = false;
  String? _error;

  
  void initState() {
    super.initState();
    _loadUser();
  }

  Future<void> _loadUser() async {
    setState(() => _isLoading = true);

    try {
      final user = await fetchUser();
      setState(() {
        _user = user;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _error = e.toString();
        _isLoading = false;
      });
    }
  }

  
  Widget build(BuildContext context) {
    if (_isLoading) return CircularProgressIndicator();
    if (_error != null) return Text('Error: $_error');
    if (_user == null) return Text('No user');

    return Text('User: ${_user!.name}');
  }
}

Common Patterns

Pattern 1: Return Early on Error

dart
Future<String?> fetchData() async {
  try {
    final response = await http.get(url);
    if (response.statusCode != 200) return null;
    return response.body;
  } catch (e) {
    return null;
  }
}

Pattern 2: Chain Multiple Async Calls

dart
Future<void> processData() async {
  final data = await fetchData();
  final processed = await processData(data);
  final result = await saveData(processed);
  print('Done: $result');
}

Pattern 3: Retry Logic

dart
Future<String> fetchWithRetry({int maxRetries = 3}) async {
  for (int i = 0; i < maxRetries; i++) {
    try {
      return await fetchData();
    } catch (e) {
      if (i == maxRetries - 1) rethrow; // Last attempt failed
      await Future.delayed(Duration(seconds: 2)); // Wait before retry
    }
  }
  throw Exception('All retries failed');
}

Future States

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

void main() async {
  final future = fetchData();

  print(future); // Instance of 'Future<String>' (uncompleted)

  final result = await future;
  print(result); // 'Data' (completed)
}

States:

  • Uncompleted - Operation in progress
  • Completed with value - Success
  • Completed with error - Failure

Async vs Sync Comparison

Synchronous (Blocks)

dart
String fetchDataSync() {
  // Blocks for 2 seconds
  sleep(Duration(seconds: 2));
  return 'Data';
}

void main() {
  print('Start');
  String data = fetchDataSync(); // Waits here (UI freezes!)
  print('Data: $data');
  print('End');
}

Asynchronous (Non-blocking)

dart
Future<String> fetchDataAsync() async {
  // Doesn't block
  await Future.delayed(Duration(seconds: 2));
  return 'Data';
}

void main() async {
  print('Start');
  String data = await fetchDataAsync(); // Waits, but doesn't block UI
  print('Data: $data');
  print('End');
}

Key Differences

FeatureSynchronousAsynchronous
Blocks UI✅ Yes❌ No
ReturnsValue directlyFuture
Use caseFast operationsSlow operations (network, I/O)
ExecutionSequentialCan run in parallel

Best Practices

PracticeRecommendation
Use async/awaitCleaner than .then() callbacks
Handle errorsAlways use try-catch
Don't block UINever use synchronous I/O
Parallel operationsUse Future.wait() when possible
TimeoutSet timeouts for network requests
Test async codeUse
text
test()
with async/await

Common Mistakes

❌ Mistake 1: Forgetting await

dart
// ❌ Bad - doesn't wait
void loadData() async {
  fetchData(); // Doesn't wait!
  print('Done'); // Prints immediately
}

// ✅ Good
void loadData() async {
  await fetchData(); // Waits
  print('Done'); // Prints after data loads
}

❌ Mistake 2: Not marking function as async

dart
// ❌ Error - can't use await without async
void loadData() {
  await fetchData(); // Error!
}

// ✅ Good
Future<void> loadData() async {
  await fetchData();
}

❌ Mistake 3: Forgetting to return Future

dart
// ❌ Bad - should return Future<void>
async void loadData() {
  await fetchData();
}

// ✅ Good
Future<void> loadData() async {
  await fetchData();
}

Key Takeaways

Future: Represents a value available in the future (async result)

async: Marks a function as asynchronous (can use await)

await: Waits for Future to complete, returns unwrapped value

Use together:

text
Future<T> functionName() async { await ... }


Resources