# Async Basics and Futures

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Asynchronous Programming
Source: https://www.devtutorials.ai/learn/dart/async/async-basics-and-futures

> How Dart runs slow work without freezing: the event loop, Futures and their states, then and catchError, async and await, and waiting for several Futures with wait, any and timeout.

## What Is Asynchronous Programming?

- **Synchronous (sync)** code runs one line after another. Each line **waits** for the one before to finish.
- **Asynchronous (async)** code can **start** a slow job, **move on**, and come back when the job is done.
- **Blocking** = the program stops and waits, doing nothing else.
- **Non-blocking** = the program keeps working while the slow job runs.

**Simple lesson:** async code starts slow work, keeps going, and picks up the result later.

### A Real-World Example

Think of ordering food at the school canteen.

- **Sync way:** you stand at the counter until your dosa is ready. The whole line behind you waits.
- **Async way:** you get a **token**, sit down, and chat with friends. When your number is called, you collect the dosa.
- The token is a promise of food **later**. In Dart, that token is called a **Future**.

Every **Run** box on this page runs on the course's Dart runner in your browser.

The runner **fast-forwards** waiting time. A 3-second delay finishes at once, but always in the right order.

## What You Will Learn

In this lesson, you will learn:

1. How Dart's event loop decides what runs next.
2. What a Future is, and its states.
3. How to create Futures, and handle them with `then`, `catchError` and `whenComplete`.
4. How `async` and `await` make async code read like normal code.
5. How to wait for many Futures, and how to give up with `timeout`.

## The Event Loop

### One Thing at a Time

Dart runs your code on **one** thread. It never runs two lines at the same moment. To handle slow jobs, it uses an **event loop**.

- **Event loop** = a loop that keeps taking the next job and running it.
- **Event queue** = jobs like timers, finished downloads, and `Future(...)` work.
- **Microtask queue** = small, urgent jobs. They **always** run before the next event.

### The Order of Things

Step through this program and watch the queues:

```dart runnable title="Sync first, then microtasks, then events"
import 'dart:async';

void main() {
  print('1. main starts');
  Future(() => print('5. event queue'));
  scheduleMicrotask(() => print('3. microtask'));
  Future.microtask(() => print('4. another microtask'));
  print('2. main ends');
}
```

- `main` runs to the end first: 1, 2.
- Then **all** microtasks: 3, 4.
- Then the event queue: 5.

A long loop in your code **blocks** the event loop. While it runs, no Future can finish and the app cannot react to taps.

Keep each job short. For heavy work, use an isolate (see **Isolates**).

**Simple lesson:** Dart finishes the current code, then empties the microtask queue, then takes the next event.

## Futures

### What Is a Future?

**Future** = an object that will hold a value **later**. `Future<int>` will give an `int` later.

A Future is always in one of these **states**:

| State | Means | Canteen token |
|---|---|---|
| **Uncompleted** | the work is still going | dosa is cooking |
| **Completed with a value** | the work finished well | "Number 42, your dosa!" |
| **Completed with an error** | the work failed | "Sorry, no dosa batter" |

### Creating Futures

| Code | Gives | Use |
|---|---|---|
| `Future(() => work())` | runs `work` later, from the event queue | start work later |
| `Future.value(5)` | a Future already holding `5` | a ready answer |
| `Future.delayed(Duration(seconds: 2), () => 5)` | `5` after 2 seconds | waiting, timers, demos |
| `Future.error(StateError('no batter'))` | a Future that fails | testing error paths |

```dart runnable title="A Future that finishes after a delay"
Future<String> cookDosa() {
  return Future.delayed(Duration(seconds: 3), () => 'Masala dosa');
}

void main() {
  print('Order placed');
  cookDosa().then((food) => print('Got: $food'));
  print('Chatting with friends...');
}
```

`Chatting with friends...` prints **before** `Got: Masala dosa`. `main` did not wait.

**Simple lesson:** a Future is a token for a value that is not ready yet.

## then, catchError and whenComplete

| Method | Runs when | Like |
|---|---|---|
| `.then((value) { ... })` | the Future gives a value | `try` |
| `.catchError((e) { ... })` | the Future fails | `catch` |
| `.whenComplete(() { ... })` | either way | `finally` |

```dart runnable title="Handling success, failure and both"
Future<int> fetchMarks(String name) {
  return Future.delayed(Duration(seconds: 1), () {
    if (name == 'Unknown') {
      throw StateError('No such student');
    }
    return 88;
  });
}

void main() {
  fetchMarks('Asha')
      .then((m) => print('Asha: $m'))
      .whenComplete(() => print('First request done'));

  fetchMarks('Unknown')
      .then((m) => print('Marks: $m'))
      .catchError((e) => print('Failed: ${e.message}'))
      .whenComplete(() => print('Second request done'));
}
```

### Chaining

Each `then` returns a **new** Future, so you can chain steps:

```dart runnable title="A chain of then steps"
void main() {
  Future.value(40)
      .then((marks) => marks + 5)
      .then((marks) => marks * 2)
      .then((total) => print('Final score: $total'));
}
```

**Simple lesson:** `then` handles the value, `catchError` handles failure, and `whenComplete` runs either way.

## async and await

### The Easy Way

Long `then` chains are hard to read. **`async` and `await`** let you write the same thing like normal code:

- **`async`** after the parameter list marks a function as async. It always returns a Future.
- **`await`** waits for a Future **inside** an async function, and gives you its value.
- While it waits, the event loop keeps running other jobs. Nothing freezes.

### Refactoring then into await

```dart runnable title="The same steps, two styles"
Future<int> getMarks() => Future.delayed(Duration(seconds: 1), () => 72);
Future<int> getBonus() => Future.delayed(Duration(seconds: 1), () => 8);

void withThen() {
  getMarks().then((m) {
    getBonus().then((b) {
      print('then style: ${m + b}');
    });
  });
}

Future<void> withAwait() async {
  var m = await getMarks();
  var b = await getBonus();
  print('await style: ${m + b}');
}

Future<void> main() async {
  withThen();
  await withAwait();
}
```

### try and catch in Async Code

With `await`, a failed Future **throws** at that line. So a normal `try` works (see **Exception Handling**):

```dart runnable title="Catching a failed Future with try"
Future<int> fetchFee(String name) async {
  await Future.delayed(Duration(seconds: 1));
  if (name.isEmpty) {
    throw ArgumentError('Name is empty');
  }
  return 1200;
}

Future<void> main() async {
  try {
    var fee = await fetchFee('');
    print('Fee: $fee');
  } on ArgumentError catch (e) {
    print('Could not fetch: ${e.message}');
  } finally {
    print('Request finished');
  }
}
```

`await` only works **inside** a function marked `async`.

Forgetting `await` is a common bug: you get the Future itself, not its value. The next line runs too early.

**Simple lesson:** mark the function `async`, put `await` before each Future, and use `try` for errors.

## Many Futures at Once

### Future.wait

**`Future.wait([...])`** waits for **all** Futures, and gives a list of their values, in order.

```dart runnable title="Three requests, waited for together"
Future<int> marks(String subject, int value, int seconds) =>
    Future.delayed(Duration(seconds: seconds), () => value);

Future<void> main() async {
  var all = await Future.wait([
    marks('Maths', 92, 3),
    marks('Science', 85, 1),
    marks('English', 78, 2),
  ]);
  print(all);
  print('Total: ${all.reduce((a, b) => a + b)}');
}
```

- The three run **at the same time**, so the total wait is 3 seconds, not 6.
- The list keeps the **order you asked**, not the order they finished.

### Future.any and timeout

- **`Future.any([...])`** gives the value of the **first** Future to finish.
- **`.timeout(duration)`** fails with a `TimeoutException` if the Future takes too long.

```dart runnable title="The fastest server, and giving up"
import 'dart:async';

Future<String> server(String name, int seconds) =>
    Future.delayed(Duration(seconds: seconds), () => name);

Future<void> main() async {
  var fastest = await Future.any([server('Mumbai', 3), server('Chennai', 1)]);
  print('Fastest: $fastest');

  try {
    var slow = await server('Delhi', 10).timeout(Duration(seconds: 2));
    print(slow);
  } on TimeoutException {
    print('Delhi took too long. Showing saved data.');
  }
}
```

`TimeoutException` comes from `dart:async`, so that import is needed.

**Easy way to remember**

- **Future** = a token for "later".
- **then / catchError / whenComplete** = try / catch / finally for tokens.
- **async + await** = wait for the token, but let others keep working.
- **wait** = all of them. **any** = the first. **timeout** = not forever.

**Simple lesson:** `wait` for all, `any` for the fastest, and `timeout` so you never wait forever.

## TL;DR

1. **Async** = start slow work, keep going, use the result later. Dart uses **one** thread and an **event loop**.
2. Order: current code, then **microtasks**, then **events**.
3. **Future** = a value later: uncompleted, completed with value, or with error.
   - Make one with `Future()`, `.value`, `.delayed`, `.error`.
4. **`then`, `catchError`, `whenComplete`**, or the easier **`async` / `await`** with `try`.
5. **`Future.wait`** (all), **`Future.any`** (first), **`.timeout`** (give up, `TimeoutException`).

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Forgetting `await` | The call gives the value | It gives a Future | The next line uses a Future, not the value. |
| `await` in a function without `async` | `await` works anywhere | Mark the function `async` | A compile error. |
| A long loop in an async app | Async means parallel | Dart runs one job at a time | The app freezes. |
| Awaiting one by one when they are independent | Order needs `await` | Use `Future.wait` | It takes much longer. |
| No `catchError` or `try` | Futures cannot fail | A failed Future throws | `Unhandled exception`. |
| Expecting `Future(...)` to run at once | It runs immediately | It runs later, from the event queue | Output order surprises you. |

## Check Yourself

## Exercises

## What to Remember

- Async code starts slow work and keeps going. Dart runs one job at a time with an event loop.
- Current code runs first, then microtasks, then events.
- A Future is a value that comes later, or an error.
- Use `async` and `await` with `try` for clear async code.
- `Future.wait` waits for all, `Future.any` takes the first, and `timeout` stops waiting.

Next: **Streams**. You will handle many values that arrive one after another.
