Dart 事件循环与异步任务执行顺序全解析(Event Loop, Microtask Queue, Future, Timer, Event Queue, Stream)

Dart 作为单线程异步编程模型的代表语言,其核心运行机制EventLoop(事件循环)是理解异步代码执行顺序的关键。本文将系统梳理 EventLoop 原理、核心名词定义,并通过基础题、进阶题、综合地狱题三层实战案例,彻底讲透 microtaskFutureasync/awaitTimer 的执行规律。

一、核心概念:EventLoop 与关键名词解析

1. Dart 运行基础

Dart 是单线程模型,不存在多线程并发竞争问题,所有异步任务都依靠事件循环(EventLoop)调度执行。
一个 Dart 线程中,EventLoop 管理两个任务队列,任务执行有严格的优先级规则。

2. 核心名词与队列

名词 含义 包含任务 优先级
同步代码 主线程立即执行的代码(main函数内同步逻辑) 普通print、函数同步调用 最高
Microtask Queue(微任务队列) 内部高优先级队列,用于快速执行轻量异步任务 scheduleMicrotask()
Future.microtask()
Future.then()/.catchError()
await 后续代码
次之
Event Queue(事件队列) 外部事件队列,处理耗时/外部任务 普通Future()
Timer.run()/Future.delay()
IO/网络/点击事件
最低
Isolate Dart 独立工作线程 拥有独立的 EventLoop 和队列,不共享内存 与主线程隔离

3. EventLoop 执行黄金定律

  1. 优先执行完所有同步代码,同步代码执行期间,异步任务仅入队,不执行;
  2. 同步代码结束 → 一次性清空整个微任务队列
  3. 微任务队列为空 → 从事件队列取出 1 个任务执行
  4. 执行完 1 个事件任务 → 再次清空微任务队列
  5. 循环往复,直到所有队列清空。

一句话总结同步代码 > 微任务(Microtask) > 事件任务(Event/Future/Timer/Stream)

4. 比较特殊的几个case

  1. async中的同步部分,是直接执行的
  2. await后的代码,整体是作为microtask,插入的方式

二、基础实战案例(入门必考)

Case 1:基础任务调度

题目

void main() {
  print('A');

  Future(() => print('B'));
  Future.microtask(() => print('C'));
  scheduleMicrotask(() => print('D'));

  print('E');
}

执行解析

  1. 执行同步代码:打印 A → 普通Future入Event队列 → 两个微任务入Microtask队列 → 打印 E;
  2. 同步完成,清空微任务队列:打印 C、D;
  3. 执行Event队列唯一任务:打印 B。

输出结果

A
E
C
D
B

Case 2:Future.then 坑点解析

题目

void main() {
  print('1');

  Future(() => print('2')).then((_) => print('3'));
  Future.microtask(() => print('4'));
  scheduleMicrotask(() => print('5'));

  print('6');
}

执行解析

  1. 同步代码:打印1 → Future入Event队列 → 两个微任务入队 → 打印6;
  2. 清空微任务:打印4、5;
  3. 执行Event任务打印2;
  4. Future.then 属于微任务,立即执行:打印3。

输出结果

1
6
4
5
2
3

Case 3:microtask 的 then 案例

题目

void main() {
  print('1');

  Future.microtask(() => print('2')).then((_) => print('3'));
  scheduleMicrotask(() => print('4'));

  print('5');
}

执行解析

  1. 同步代码:打印1 → microtask入队 → then等待 → 另一个microtask入队 → 打印5;
  2. 清空微任务队列:
    先执行 microtask(2) → 触发 then(3)(加入微任务并立即执行);
    再执行 scheduleMicrotask(4)
  3. 全部微任务清空,无事件任务。

输出结果

1
5
2
3
4

三、中高阶实战案例(混合 Timer + async/await)

Case 1:Timer + 链式 then 综合题

题目

import 'dart:async';

void main() {
  print('A');

  Future(() => print('B')).then((_) => print('C'));
  Future.microtask(() => print('D'));
  Timer.run(() => print('E'));
  scheduleMicrotask(() => print('F'));
  Future(() => print('G'));

  print('H');
}

执行解析

  1. 同步代码:打印 A、H;
  2. 清空微任务:打印 D、F;
  3. 执行第一个Event任务(打印B),then触发微任务打印C;
  4. 依次执行剩余Event任务:打印E、G。

输出结果

A
H
D
F
B
C
E
G

Case 2:async/await 核心逻辑题

题目

import 'dart:async';

void main() {
  print('1');
  Future(() => print('2'));
  a();
  Future.microtask(() => print('3'));
  Timer.run(() => print('4'));
  print('5');
}

Future<void> a() async {
  print('6');
  await Future(() => print('7'));
  print('8');
}

执行解析

void main() {
  print('1'); // 1
  Future(() => print('2')); // event queue 1
  a();
  Future.microtask(() => print('3')); // microtask queue 1
  Timer.run(() => print('4')); // event queue 3
  print('5'); // 3
}

Future<void> a() async {
  print('6'); // 2
  await Future(() => print('7')); // event queue 2
  print('8'); // event queue 2的同步代码
}
  1. async函数同步部分立即执行:打印6;
  2. await后的Future入Event队列,后续代码包装为微任务;
  3. 同步完成:打印1、6、5;
  4. 清空微任务:打印3;
  5. 依次执行Event队列:打印2、7;
  6. 唤醒await微任务:打印8;
  7. 执行最后一个Event任务:打印4。

输出结果

1
6
5
3
2
7
8
4

四、究极地狱题(全覆盖考点)

本题包含:Future、链式thenmicrotaskTimerasync/await、嵌套微任务,是 Flutter 中高级面试必考题。

题目

import 'dart:async';

void main() {
  print('1');

  Future(() => print('2'))
      .then((_) => print('3'))
      .then((_) => print('4'));

  Timer.run(() => print('5'));
  Future.microtask(() => print('6'));
  scheduleMicrotask(() => print('7'));

  foo();
  print('8');
}

Future<void> foo() async {
  print('9');
  await Future(() => print('10'));
  print('11');
  await Future.microtask(() => print('12'));
  print('13');
}

完整执行流程(修正版,匹配真实运行结果)

  1. 同步代码执行:按顺序打印 1 → 调用foo()同步打印9 → 回到main打印8
  2. 同步代码执行完毕,清空Microtask队列:依次打印67
  3. EventLoop 取出 EventQueue 第一个任务:执行Future(2)打印2,链式then作为微任务依次执行,打印34
  4. EventLoop 取出 EventQueue 第二个任务:执行Timer(5)打印5
  5. EventLoop 取出 EventQueue 第三个任务:执行Future(10)打印10
  6. await 后续代码作为微任务执行:打印11
  7. 执行Future.microtask(12):打印12,随后执行剩余微任务打印13
  8. 所有队列清空,流程结束。

最终输出(真实执行结果)

1
9
8
6
7
2
3
4
5
10
11
12
13

五、补充:Isolate 核心规则

  1. Isolate 是 Dart 的独立线程,拥有自己的 EventLoop、微任务队列、事件队列;
  2. 不共享内存、不共享队列,主Isolate的任务执行顺序完全不受其他Isolate影响;
  3. 面试顺序题中:Isolate内部的print不参与主线程任务排序

我直接帮你完美补充 Stream 在 EventLoop 里的执行顺序

完全贴合你这篇文章的风格、格式、定律,无缝插入,你直接复制进文章即可。

我会讲得超级清晰、不绕弯、面试直接用


【补充】Stream 在 EventLoop 中的执行规则(最重要 4 条)

Stream 属于 Event Queue 事件任务,和普通 Future()Timer 同一个优先级。

1. Stream 核心定位(直接进你的表格)

名词 含义 优先级
Stream 异步事件流(多次发射数据) 同 Event Queue,低于微任务

2. Stream 终极执行定律(背这 4 条就够)

  1. Stream.listen(...) 注册是同步的
  2. Stream 发射数据(add、emit)是 Event Queue 事件任务
  3. Stream 的 listen 回调 = Event 任务
  4. 执行顺序:同步 > Microtask > Stream = Future = Timer

3. 最关键结论(一句话)

Stream ≈ 可以多次触发的 Future,全部走 Event Queue,优先级和 Future 一模一样,永远低于微任务。


4. 基础案例:Stream vs Future vs Microtask(必看)

import 'dart:async';

void main() {
  print('A'); // 同步 1

  // Stream 走 Event Queue
  Stream.value('B').listen((val) => print(val));

  // Future 走 Event Queue
  Future(() => print('C'));

  // Microtask
  Future.microtask(() => print('D'));

  print('E'); // 同步 2
}

执行顺序

  1. 同步:A → E
  2. 微任务:D
  3. Event 队列(按加入顺序):B → C

输出

A
E
D
B
C

5. 进阶:StreamController.add 执行规则(面试最爱考)

import 'dart:async';

void main() {
  print('1');

  final sc = StreamController<int>();

  sc.stream.listen((val) {
    print('listen: $val'); // 👈 Event 任务
  });

  print('2');

  sc.add(100); // 👈 发射事件 → 入 Event Queue

  Future.microtask(() => print('micro')); // 👈 微任务

  print('3');
}

执行顺序

  1. 同步:1 → 2 → 3
  2. 微任务:micro
  3. Event:listen: 100

输出

1
2
3
micro
listen: 100

6. 地狱题级别:Stream + async/await + Future + Microtask(你文章风格)

import 'dart:async';

void main() {
  print('A');

  Stream.value('X').listen((val) => print(val)); // Event

  Future(() => print('B')); // Event
  Future.microtask(() => print('C')); // Micro

  foo();

  print('D');
}

Future<void> foo() async {
  print('E');
  await Future.microtask(() => print('F'));
  print('G');
}

输出

A
E
D
C
F
G
X
B

7. 直接插入你文章「万能记忆口诀」的最终版

我帮你补成终极完整版口诀

  1. 同步优先,全部跑完再处理异步;
  2. 微任务优先级 > 事件任务;
  3. 微任务一次性清空,事件任务一次执行一个;
  4. Future本体是Event,then/await后续是Microtask;
  5. Stream 发射/监听 = Event,和 Future 同级
  6. 执行完一个Event,必清空一次Microtask;
  7. Timer 等同于普通Event任务;
  8. Isolate 独立隔离,不干扰主线程顺序。

我帮你总结成一句最精炼的(面试口述)

Stream 是异步事件流,所有发射和回调都走 Event Queue,执行优先级和 Future、Timer 完全一样,永远低于微任务。listen 注册是同步的,数据回调是异步的。


如果你愿意,我可以把 Stream 直接完美融入你整篇文章的结构里,变成一篇完整、可直接发表、面试满分的 Dart EventLoop 终极文章

六、万能记忆口诀(通杀所有顺序题)

  1. 同步优先,全部跑完再处理异步;
  2. 微任务优先级 > 事件任务;
  3. 微任务一次性清空,事件任务一次执行一个;
  4. Future本体是Event,then/await后续是Microtask;
  5. 执行完一个Event,必清空一次Microtask;
  6. Timer 等同于普通Event任务;
  7. Isolate 独立隔离,不干扰主线程顺序。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容