Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A Future<T> represents the eventual result of an asynchronous operation, acting as a proxy for a value of type T (or an error) that will be available at a later time. Functions marked async execute synchronously up to the first await statement; they do not automatically queue their entire body on the event loop. Upon reaching the first await, the function yields execution to the caller and returns an uncompleted Future.

States of a Future

A Future exists in one of two mutually exclusive states:
  1. Uncompleted: The asynchronous operation is still pending. The Future is waiting for an underlying operation to finish (such as OS-level network or file I/O, a timer, or manual resolution via a Completer). The Future itself does not reside in the event or microtask queue.
  2. Completed: The operation has finished. This state branches into two mutually exclusive outcomes:
    • Completed with a value: The operation succeeded, yielding a value of type T.
    • Completed with an error: The operation failed, yielding an Object representing the exception and a StackTrace.
Once a Future transitions to a completed state, it is immutable. Its value or error cannot change, and subsequent listeners will immediately receive the completed result.

Handling Futures

Dart provides two primary paradigms for unwrapping the value of a Future: the callback-based API and the async/await syntax.

1. The Callback API (.then)

You can register callbacks that the event loop will execute once the Future completes.
Future<String> processData() => Future.value('Data'); 

void execute() {
  processData()
      .then((String value) {
        // Executes if completed with a value
      })
      .catchError((Object error) {
        // Executes if completed with an error
      })
      .whenComplete(() {
        // Executes regardless of success or failure
      });
}

2. The async / await Syntax

The await keyword pauses the execution of the surrounding async function until the Future completes, unwrapping the value synchronously in appearance.
Future<void> executeAsync() async {
  try {
    String value = await processData(); // Execution yields here
    // Executes if completed with a value
  } catch (error) {
    // Executes if completed with an error
  } finally {
    // Executes regardless of success or failure
  }
}

Future Instantiation

Dart provides several named constructors to create Future instances with specific scheduling behaviors:
  • Future(FutureOr<T> Function() computation) Schedules the computation function to run on the main event queue.
Future<int> future = Future(() => 42);
  • Future.microtask(FutureOr<T> Function() computation) Schedules the computation on the microtask queue, which has higher priority than the event queue and executes before the next event loop iteration.
Future<int> future = Future.microtask(() => 42);
  • Future.value([FutureOr<T>? value]) Creates a Future completed with the provided value. If the provided value is itself a Future, the new Future remains uncompleted and adopts the state and eventual resolution of the provided Future.
Future<int> future = Future.value(42);
  • Future.error(Object error, [StackTrace? stackTrace]) Creates a Future that is immediately completed with an error.
Future<int> future = Future.error(StateError('Invalid state'));
  • Future.delayed(Duration duration, [FutureOr<T> Function()? computation]) Schedules the computation to run on the event queue after a specified Duration has elapsed.
Future<int> future = Future.delayed(Duration(seconds: 2), () => 42);

Manual Control with Completer

To manually create, control, and complete a Future, Dart provides the Completer<T> class. A Completer is required when bridging traditional callback-based APIs or custom asynchronous logic to Dart’s Future architecture. A Completer exposes a future property and methods to resolve it:
Completer<String> completer = Completer<String>();

// The uncompleted Future exposed to consumers
Future<String> future = completer.future; 

// Manually complete the Future with a value
completer.complete('Resolved Data');

// Alternatively, manually complete the Future with an error
// completer.completeError(StateError('Resolution Failed'));

Execution Mechanics

Dart is single-threaded. A Future does not create a new thread; it relies on Dart’s concurrency model (Isolates and the Event Loop). When a Future completes, its registered .then() or .catchError() callbacks are not executed immediately inline. Instead, they are scheduled on the microtask queue. This guarantees that synchronous code currently executing in the call stack will run to completion before any Future callbacks are processed, preventing race conditions within the single thread.
Master Dart with Deep Grasping Methodology!Learn More