Menu
Coddy logo textTech

Futures & async/await

Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 76 of 110.

In real applications, many operations take time - fetching data from a server, reading files, or waiting for user input. Dart handles these with Future, which represents a value that will be available sometime in the future.

A Future is like a promise: "I'll give you the result when it's ready." You can create one using Future.delayed() to simulate an operation that takes time:

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

To work with the result of a Future, use async and await. Mark your function as async, then use await to pause execution until the Future completes:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Without await, you'd get a Future<String> instead of the actual string. The await keyword unwraps the Future and gives you the value inside. Note that any function using await must be marked async, and it automatically returns a Future.

You can also return values directly from async functions - Dart wraps them in a Future automatically:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // Automatically wrapped in Future<int>
}
challenge icon

Challenge

Easy

Let's build a weather service that simulates fetching weather data from different cities! You'll practice using Future, async, and await to handle operations that take time to complete.

You'll organize your code into two files:

  • weather_service.dart: Create a WeatherService class that simulates fetching weather information. Your class should have:
    • A method fetchTemperature(String city) that returns a Future<int>. Use Future.delayed() with a duration of 100 milliseconds to simulate network delay. The method should return a temperature based on the city name: return the length of the city name multiplied by 3.
    • A method fetchCondition(String city) that returns a Future<String>. Use Future.delayed() with 100 milliseconds delay. Return 'Sunny' if the city name has an even number of characters, otherwise return 'Cloudy'.
    • An async method getFullReport(String city) that returns a Future<String>. This method should await both fetchTemperature and fetchCondition, then return a formatted string: '[city]: [temperature]C, [condition]'
  • main.dart: Import your weather service and demonstrate how async operations work. Your main function should be async and:
    • Create a WeatherService instance
    • Print Fetching weather data...
    • Await and print the full report for 'Paris'
    • Await and print the full report for 'Tokyo'
    • Await and print the full report for 'London'
    • Print Done!

Notice how each call to getFullReport waits for both the temperature and condition to be fetched before returning the combined result. The await keyword pauses execution until each Future completes!

Expected output:

Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!

Cheat sheet

A Future represents a value that will be available in the future. It's used for operations that take time, like fetching data or reading files.

Create a Future using Future.delayed():

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Use async and await to work with Futures. Mark the function as async and use await to pause execution until the Future completes:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

The await keyword unwraps the Future and gives you the actual value. Without it, you'd get a Future<String> instead of the string.

Any function using await must be marked async and automatically returns a Future.

Return values from async functions are automatically wrapped in a Future:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // Automatically wrapped in Future<int>
}

Try it yourself

import 'weather_service.dart';

Future<void> main() async {
  // TODO: Create a WeatherService instance
  
  // TODO: Print 'Fetching weather data...'
  
  // TODO: Await and print the full report for 'Paris'
  
  // TODO: Await and print the full report for 'Tokyo'
  
  // TODO: Await and print the full report for 'London'
  
  // TODO: Print 'Done!'
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming