Asynchronous programming is a key feature in Dart that allows you to perform tasks without blocking the main thread. This is particularly useful for tasks that take a long time to complete, such as network requests, file I/O, or database operations. In this section, we will cover the basics of asynchronous programming in Dart, including Futures, async/await, and handling asynchronous errors.
Key Concepts
- Futures: Represents a potential value or error that will be available at some time in the future.
- async/await: Keywords used to write asynchronous code in a more readable and maintainable way.
- Error Handling: Techniques to handle errors in asynchronous code.
Futures
A Future
in Dart is an object that represents a value that will be available at some point in the future. It can either complete with a value or with an error.
Creating a Future
You can create a Future
using the Future
constructor or by using async functions.
Future<String> fetchUserOrder() { // Imagine that this function is fetching user order from a server return Future.delayed(Duration(seconds: 2), () => 'Large Latte'); }
Using then() and catchError()
You can handle the result of a Future
using the then()
method and handle errors using the catchError()
method.
void main() { fetchUserOrder().then((order) { print('Order: $order'); }).catchError((error) { print('Error: $error'); }); }
Practical Example
Future<int> fetchData() { return Future.delayed(Duration(seconds: 3), () => 42); } void main() { print('Fetching data...'); fetchData().then((value) { print('Data received: $value'); }).catchError((error) { print('Error: $error'); }); }
async and await
The async
and await
keywords provide a more readable way to write asynchronous code. An async
function returns a Future
, and you can use the await
keyword to wait for a Future
to complete.
Using async and await
Future<void> printOrderMessage() async { var order = await fetchUserOrder(); print('Order: $order'); } void main() { print('Fetching order...'); printOrderMessage(); }
Practical Example
Future<int> fetchData() async { await Future.delayed(Duration(seconds: 3)); return 42; } void main() async { print('Fetching data...'); try { int data = await fetchData(); print('Data received: $data'); } catch (error) { print('Error: $error'); } }
Error Handling in Asynchronous Code
Handling errors in asynchronous code is crucial to ensure your application can gracefully handle unexpected situations.
Using try-catch with async/await
Future<void> printOrderMessage() async { try { var order = await fetchUserOrder(); print('Order: $order'); } catch (error) { print('Error: $error'); } } void main() { print('Fetching order...'); printOrderMessage(); }
Practical Example
Future<int> fetchData() async { await Future.delayed(Duration(seconds: 3)); throw Exception('Failed to fetch data'); } void main() async { print('Fetching data...'); try { int data = await fetchData(); print('Data received: $data'); } catch (error) { print('Error: $error'); } }
Exercises
Exercise 1: Fetch User Data
Write a function fetchUserData
that simulates fetching user data from a server. The function should return a Future
that completes with a user name after a 2-second delay. Use async
and await
to print the user name.
Solution
Future<String> fetchUserData() async { return Future.delayed(Duration(seconds: 2), () => 'John Doe'); } void main() async { print('Fetching user data...'); try { String userName = await fetchUserData(); print('User name: $userName'); } catch (error) { print('Error: $error'); } }
Exercise 2: Handle Errors
Modify the fetchUserData
function to throw an error if the user name is not found. Handle the error in the main
function using try-catch
.
Solution
Future<String> fetchUserData() async { return Future.delayed(Duration(seconds: 2), () { throw Exception('User not found'); }); } void main() async { print('Fetching user data...'); try { String userName = await fetchUserData(); print('User name: $userName'); } catch (error) { print('Error: $error'); } }
Conclusion
In this section, we covered the basics of asynchronous programming in Dart, including Futures, async/await, and error handling. Asynchronous programming is essential for building responsive applications, and mastering these concepts will help you write more efficient and maintainable code. In the next section, we will dive into Streams, which allow you to work with sequences of asynchronous events.
Dart Programming Course
Module 1: Introduction to Dart
- Introduction to Dart
- Setting Up the Development Environment
- Your First Dart Program
- Basic Syntax and Structure