Dart Core Optimization Series
Part 6: The "Heart" of Dart - Understanding the Event Loop
Of course. This time, we'll explore a core concept that is the "heart" controlling how Dart handles asynchronous tasks and keeps your application responsive: the Event Loop.
The Scenario 📝
- The Question: A developer knows that Dart is single-threaded. So how can a Flutter app download data from the network, handle user taps, and run an animation all at the same time without "freezing"?
What is the Event Loop? 🧐
The Event Loop is a mechanism that runs continuously in the background. Its only job is to check if there is any "work" to do, then take that work and execute it.
All of your Dart code runs on a single main thread. To avoid getting stuck, the Event Loop manages work using two main queues.
The Two Important Queues
The Event Queue:
- Contains all events coming from the outside world:
- I/O operations (data returned from the network, a file read finishing).
- User interactions (taps, clicks, key presses).
- Timers (
Future.delayed).
- Analogy: This is the main queue, like food orders coming from customers into the kitchen.
- Contains all events coming from the outside world:
The Microtask Queue:
- Has a higher priority than the Event Queue.
- Used for very short tasks that need to be executed immediately after the current piece of code finishes, before the Event Loop has a chance to do anything else (e.g.,
Future.microtask()). - Analogy: This is the manager's "urgent note" that must be handled right away.
How the Event Loop Works
The Event Loop's process is simple but effective:
- Finish the current task.
- Look at the Microtask Queue. If there's work, execute all tasks in it until the queue is empty.
- Only when the Microtask Queue is empty, it looks at the Event Queue.
- Take one event from the Event Queue and execute it.
- Repeat from step 1.
How Does async/await Work?
async/await is just a "pretty" way to work with the Event Loop.
When you write:
dart
Future<void> fetchData() async {
print('Starting to fetch data...');
final data = await http.get(...); // <--- The pause point
print('Data has arrived: $data');
}Here's what happens:
http.get(...)is called. It asks the operating system to start downloading data (this happens on a different OS thread, not the Dart thread).- The
awaitkeyword tells the Event Loop: "Pause thefetchDatafunction here. Put the rest of the function (print(...)) into the Event Queue to be run later. The main thread is now free, so go do other work." - The Event Loop is now free and continues to process other events in the queue (e.g., redrawing the UI, handling a tap), which keeps the app from freezing.
- When the data download is complete, a "download finished" event is added to the Event Queue.
- Eventually, the Event Loop will pick up that event and execute the rest of the
fetchDatafunction.
Conclusion:
- The Event Loop is the core mechanism that allows single-threaded Dart to handle many tasks concurrently without blocking.
async/awaitis just syntax that makes it easy for you to "delegate" work to external systems and "schedule" the results to be processed later via the Event Loop.- Understanding the Event Loop helps you know why I/O tasks (
await) don't freeze your app, but long-running CPU tasks (like a heavy calculation in a loop) do (because they never give control back to the Event Loop).