Each isolate runs one event loop with two queues. The microtask queue is drained completely before the next item from the event queue (timers, I/O, messages) runs.
Dart Expert · Lesson 1 · On the house
The event loop: microtasks and events
Microtask queue before event queue, scheduleMicrotask, and ordering puzzles. Lesson 1 is free — on the house.
Lessons · Dart Expert · Lesson 1 of 10 · On the house
The event loop: microtasks and events
Microtask queue before event queue, scheduleMicrotask, and ordering puzzles.

scheduleMicrotask(f) and continuations of already-completed Futures go to the microtask queue. Timer.run(f) and Future(f) go to the event queue. Future.delayed(Duration.zero, f) is also an event.
Synchronous code in main runs first, then all microtasks, then events one at a time, draining microtasks again after each event.
A microtask that keeps scheduling microtasks starves timers and I/O forever. Keep microtasks short.
Code after an await resumes as a microtask once the awaited Future completes, which is why await null yields to other pending microtasks but not to events.
queue ordering
import 'dart:async';
void main() {
print('A');
Timer.run(() => print('E'));
Future(() => print('F'));
scheduleMicrotask(() => print('M'));
Future.value(1).then((_) => print('T'));
print('B');
}
Quiz
Quiz
Quiz
Quiz
Check
Match the still for: The event loop: microtasks and events.
Open-book: the answers are on this page. Pass every quiz and check (5) to mark the lesson done. This visit: 0/5.