The Event Loop and Futures

24.1 The Event Loop

Each isolate runs a single-threaded event loop with two queues:

The microtask queue (high priority: scheduleMicrotask, completed Future callbacks)

The event queue (I/O, timers, user events, messages from other isolates)

Code runs to completion. Asynchronous operations schedule callbacks rather than blocking.

void main() {
  print('1 sync');
  Future(() => print('4 event queue'));
  scheduleMicrotask(() => print('3 microtask'));
  Future.value(1).then((_) => print('3b microtask (completed future)'));
  print('2 sync');
}
// Output: 1 sync, 2 sync, 3 microtask, 3b..., 4 event queue

24.2 Futures

A Future<T> represents a value (or error) that will be available later. Its states are uncompleted, completed with a value, and completed with an error.

Future<String> fetchUser() => Future.delayed(const Duration(seconds: 1), () => 'Ana');

void main() {
  fetchUser()
      .then((user) => print('User: $user'))
      .catchError((e) => print('Error: $e'))
      .whenComplete(() => print('Done'));

  final immediate = Future.value(42);
  final failed = Future<int>.error(StateError('boom'));
  final sync = Future.sync(() => compute());
  final delayed = Future.delayed(const Duration(milliseconds: 500));
}

24.3 Combining Futures

final results = await Future.wait([fetchA(), fetchB(), fetchC()]);    // all (fails fast on the first error)
final (user, posts) = await (fetchUser(), fetchPosts()).wait;        // records of futures (Dart 3)
final fastest = await Future.any([mirror1(), mirror2()]);             // first to complete
final value = await fetchUser().timeout(const Duration(seconds: 5), onTimeout: () => 'fallback');
await Future.forEach([1, 2, 3], (n) async => await process(n));      // sequential
final results2 = await Future.wait(urls.map(download), eagerError: true);

24.4 Completer

import 'dart:async';

Future<String> legacyToFuture() {
  final completer = Completer<String>();
  legacyApi(onSuccess: completer.complete, onError: completer.completeError);
  return completer.future;
}