Flutter Interview Handbook

Asynchronous Execution

100%

Asynchronous Execution

Dart is a single-threaded execution environment that relies on asynchronous primitives (Future, Stream, and async/await) to perform non-blocking I/O and heavy computational scheduling without freezing the main thread.


1. Core Primitives: Future and Stream

  • Future<T>: Represents a computation that delivers a single value or error asynchronously in the future (similar to Promise in JavaScript or Task in C#).
  • Stream<T>: Represents a sequence of asynchronous events produced over time.

Future States

A Future exists in one of two states:

  1. Uncompleted: The asynchronous operation is currently running or pending in the event queue.
  2. Completed: The operation finished, yielding either a Value (T) or an Error (Object).

2. Under The Hood: async/await State Machine Transformation

When you label a method with async, the Dart compiler transforms the function body into an asynchronous state machine.

State Machine Breakdown

  1. Synchronous Execution Until First await: Code before the first await keyword executes synchronously when the function is invoked!
  2. Suspension & Continuation: When the execution reaches await expr:
    • The expression expr is evaluated to a Future.
    • The remaining portion of the function is registered as a .then() callback continuation.
    • Execution control immediately returns to the caller.
  3. Event Loop Resumption: When expr completes, its callback is scheduled onto the event loop queue to resume execution of the remaining state machine.
[ Function Called ] 


 (Executes Synchronously)

    [ await expr ] ──► Registers Continuation on Event Loop ──► Return Control to Caller

         ▼ (When Future Completes)
 [ Resume State Machine ] ──► Execute Remaining Code

3. Single-Subscription vs. Broadcast Streams

Dart Streams come in two distinct flavors:

FeatureSingle-Subscription StreamBroadcast Stream
Listener CountMaximum of 1 listener.Multiple listeners allowed.
Event BufferingBuffers events until a listener subscribes.Events are fired immediately; dropped if no listener is present.
Use CaseFile I/O, HTTP response body streaming.UI Event Buses, State Management (BehaviorSubject), WebSocket feeds.

4. Error Handling & Zones (runZonedGuarded)

Asynchronous errors in Dart cannot be caught by standard outer try-catch blocks if they occur inside un-awaited background futures.

Zones as Execution Contexts

A Zone represents an isolated execution context with scoped error handlers, print overrides, and zone-local values. Wrapping code inside runZonedGuarded catches all unhandled asynchronous exceptions:

import 'dart:async';

void main() {
  runZonedGuarded(() {
    // Application entry point
    performAsyncTask();
  }, (error, stackTrace) {
    // Intercepts ALL unhandled async errors in this Zone
    print('Caught by Zone: $error');
  });
}

5. Trade-offs & Production Considerations

  • Parallelism Illusion: async/await does NOT run code on a background CPU thread! A long CPU-bound loop inside an async function will still freeze the UI thread. CPU-intensive operations require Isolates.
  • Memory Leak Traps: Forgetting to cancel a StreamSubscription inside a Flutter Widget’s dispose() method keeps the widget reference in memory, creating severe memory leaks.