Сегодня расскажу, как устроен Event Loop и почему понимание его работы критически важно для написания эффективного асинхронного кода.
Event Loop — это механизм управления асинхронностью, который обрабатывает задачи (events) в определенном порядке. Он позволяет выполнять операции ввода-вывода и другие длительные процессы без блокировки основного потока.
Основные компоненты
✔️Future — объект, представляющий результат асинхронной операции, который станет доступен в будущем
✔️Stream — поток асинхронных данных, который может передавать несколько значений со временем
✔️Event Loop — центральный механизм, управляющий очередями задач и их последовательным выполнением
✔️Система очередей
Event Loop работает с двумя типами очередей:
▪️Microtask Queue — очередь микрозадач с наивысшим приоритетом. Выполняется сразу после завершения синхронного кода, до обработки основных событий.
▪️Event Queue — основная очередь событий, содержащая таймеры, операции ввода-вывода, Future и другие задачи.
Порядок: Сначала синхронный код → все микрозадачи → задачи из Event Queue.
Пример
import 'dart:async';
void main() {
print('Начало');
Timer(Duration(seconds: 1), () => print('Timer'));
scheduleMicrotask(() => print('Microtask 1'));
Future(() => print('Future')).then((_) => print('Future then'));
scheduleMicrotask(() => print('Microtask 2'));
print('Конец');
}
Вывод:
Начало
Конец
Microtask 1
Microtask 2
Future
Future then
Timer
Сначала выполняется синхронный код (Начало, Конец), затем обе микрозадачи, и только после этого Future и Timer из основной очереди.
Работа с async/await
Ключевые слова async и await упрощают работу с асинхронным кодом, делая его похожим на синхронный:
Future<void> fetch() async {
print('Загрузка...');
await Future.delayed(Duration(seconds: 2));
print('Готово!');
}
void main() async {
print('Старт');
await fetch();
print('Финиш');
}Вывод:
Старт
Загрузка...
(пауза 2 секунды)
Готово!
Финиш
Оператор await приостанавливает выполнение функции до завершения Future, но не блокирует Event Loop — он может обрабатывать другие задачи.
Итого
Синхронный код всегда выполняется первым, микрозадачи имеют приоритет перед обычными событиями, а Future и Timer обрабатываются в порядке добавления в Event Queue.
❓Закрепим знания задачкой
В какой последовательности будут выведены значения?
import 'dart:async';
void main() {
print('1');
Future(() => print('2')).then((_) {
print('3');
scheduleMicrotask(() => print('4'));
});
scheduleMicrotask(() => print('5'));
Future(() => print('6'));
print('7');
}
