Dart 作為單線程異步編程模型的代表語言,其核心運行機制EventLoop(事件循環(huán))是理解異步代碼執(zhí)行順序的關(guān)鍵。本文將系統(tǒng)梳理 EventLoop 原理、核心名詞定義,并通過基礎(chǔ)題、進階題、綜合地獄題三層實戰(zhàn)案例,徹底講透 microtask、Future、async/await、Timer 的執(zhí)行規(guī)律。
一、核心概念:EventLoop 與關(guān)鍵名詞解析
1. Dart 運行基礎(chǔ)
Dart 是單線程模型,不存在多線程并發(fā)競爭問題,所有異步任務(wù)都依靠事件循環(huán)(EventLoop)調(diào)度執(zhí)行。
一個 Dart 線程中,EventLoop 管理兩個任務(wù)隊列,任務(wù)執(zhí)行有嚴(yán)格的優(yōu)先級規(guī)則。
2. 核心名詞與隊列
| 名詞 | 含義 | 包含任務(wù) | 優(yōu)先級 |
|---|---|---|---|
| 同步代碼 | 主線程立即執(zhí)行的代碼(main函數(shù)內(nèi)同步邏輯) | 普通print、函數(shù)同步調(diào)用 | 最高 |
| Microtask Queue(微任務(wù)隊列) | 內(nèi)部高優(yōu)先級隊列,用于快速執(zhí)行輕量異步任務(wù) |
scheduleMicrotask()Future.microtask()Future.then()/.catchError()await 后續(xù)代碼 |
次之 |
| Event Queue(事件隊列) | 外部事件隊列,處理耗時/外部任務(wù) | 普通Future()Timer.run()/Future.delay()IO/網(wǎng)絡(luò)/點擊事件 |
最低 |
| Isolate | Dart 獨立工作線程 | 擁有獨立的 EventLoop 和隊列,不共享內(nèi)存 | 與主線程隔離 |
3. EventLoop 執(zhí)行黃金定律
- 優(yōu)先執(zhí)行完所有同步代碼,同步代碼執(zhí)行期間,異步任務(wù)僅入隊,不執(zhí)行;
- 同步代碼結(jié)束 → 一次性清空整個微任務(wù)隊列;
- 微任務(wù)隊列為空 → 從事件隊列取出 1 個任務(wù)執(zhí)行;
- 執(zhí)行完 1 個事件任務(wù) → 再次清空微任務(wù)隊列;
- 循環(huán)往復(fù),直到所有隊列清空。
一句話總結(jié):同步代碼 > 微任務(wù)(Microtask) > 事件任務(wù)(Event/Future/Timer/Stream)
4. 比較特殊的幾個case
- async中的同步部分,是直接執(zhí)行的
- await后的代碼,整體是作為microtask,插入的方式
二、基礎(chǔ)實戰(zhàn)案例(入門必考)
Case 1:基礎(chǔ)任務(wù)調(diào)度
題目
void main() {
print('A');
Future(() => print('B'));
Future.microtask(() => print('C'));
scheduleMicrotask(() => print('D'));
print('E');
}
執(zhí)行解析
- 執(zhí)行同步代碼:打印 A → 普通Future入Event隊列 → 兩個微任務(wù)入Microtask隊列 → 打印 E;
- 同步完成,清空微任務(wù)隊列:打印 C、D;
- 執(zhí)行Event隊列唯一任務(wù):打印 B。
輸出結(jié)果
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');
}
執(zhí)行解析
- 同步代碼:打印1 → Future入Event隊列 → 兩個微任務(wù)入隊 → 打印6;
- 清空微任務(wù):打印4、5;
- 執(zhí)行Event任務(wù)打印2;
- Future.then 屬于微任務(wù),立即執(zhí)行:打印3。
輸出結(jié)果
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');
}
執(zhí)行解析
- 同步代碼:打印1 → microtask入隊 → then等待 → 另一個microtask入隊 → 打印5;
- 清空微任務(wù)隊列:
先執(zhí)行microtask(2)→ 觸發(fā)then(3)(加入微任務(wù)并立即執(zhí)行);
再執(zhí)行scheduleMicrotask(4); - 全部微任務(wù)清空,無事件任務(wù)。
輸出結(jié)果
1
5
2
3
4
三、中高階實戰(zhàn)案例(混合 Timer + async/await)
Case 1:Timer + 鏈?zhǔn)?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');
}
執(zhí)行解析
- 同步代碼:打印 A、H;
- 清空微任務(wù):打印 D、F;
- 執(zhí)行第一個Event任務(wù)(打印B),then觸發(fā)微任務(wù)打印C;
- 依次執(zhí)行剩余Event任務(wù):打印E、G。
輸出結(jié)果
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');
}
執(zhí)行解析
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的同步代碼
}
-
async函數(shù)同步部分立即執(zhí)行:打印6; -
await后的Future入Event隊列,后續(xù)代碼包裝為微任務(wù); - 同步完成:打印1、6、5;
- 清空微任務(wù):打印3;
- 依次執(zhí)行Event隊列:打印2、7;
- 喚醒await微任務(wù):打印8;
- 執(zhí)行最后一個Event任務(wù):打印4。
輸出結(jié)果
1
6
5
3
2
7
8
4
四、究極地獄題(全覆蓋考點)
本題包含:Future、鏈?zhǔn)?code>then、microtask、Timer、async/await、嵌套微任務(wù),是 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');
}
完整執(zhí)行流程(修正版,匹配真實運行結(jié)果)
-
同步代碼執(zhí)行:按順序打印
1→ 調(diào)用foo()同步打印9→ 回到main打印8; -
同步代碼執(zhí)行完畢,清空Microtask隊列:依次打印
6、7; -
EventLoop 取出 EventQueue 第一個任務(wù):執(zhí)行
Future(2)打印2,鏈?zhǔn)?code>then作為微任務(wù)依次執(zhí)行,打印3、4; -
EventLoop 取出 EventQueue 第二個任務(wù):執(zhí)行
Timer(5)打印5; -
EventLoop 取出 EventQueue 第三個任務(wù):執(zhí)行
Future(10)打印10; -
await 后續(xù)代碼作為微任務(wù)執(zhí)行:打印
11; -
執(zhí)行
Future.microtask(12):打印12,隨后執(zhí)行剩余微任務(wù)打印13; - 所有隊列清空,流程結(jié)束。
最終輸出(真實執(zhí)行結(jié)果)
1
9
8
6
7
2
3
4
5
10
11
12
13
五、補充:Isolate 核心規(guī)則
- Isolate 是 Dart 的獨立線程,擁有自己的 EventLoop、微任務(wù)隊列、事件隊列;
- 不共享內(nèi)存、不共享隊列,主Isolate的任務(wù)執(zhí)行順序完全不受其他Isolate影響;
- 面試順序題中:Isolate內(nèi)部的print不參與主線程任務(wù)排序。
我直接幫你完美補充 Stream 在 EventLoop 里的執(zhí)行順序
完全貼合你這篇文章的風(fēng)格、格式、定律,無縫插入,你直接復(fù)制進文章即可。
我會講得超級清晰、不繞彎、面試直接用。
【補充】Stream 在 EventLoop 中的執(zhí)行規(guī)則(最重要 4 條)
Stream 屬于 Event Queue 事件任務(wù),和普通 Future()、Timer 同一個優(yōu)先級。
1. Stream 核心定位(直接進你的表格)
| 名詞 | 含義 | 優(yōu)先級 |
|---|---|---|
| Stream | 異步事件流(多次發(fā)射數(shù)據(jù)) | 同 Event Queue,低于微任務(wù) |
2. Stream 終極執(zhí)行定律(背這 4 條就夠)
- Stream.listen(...) 注冊是同步的
- Stream 發(fā)射數(shù)據(jù)(add、emit)是 Event Queue 事件任務(wù)
- Stream 的 listen 回調(diào) = Event 任務(wù)
- 執(zhí)行順序:同步 > Microtask > Stream = Future = Timer
3. 最關(guān)鍵結(jié)論(一句話)
Stream ≈ 可以多次觸發(fā)的 Future,全部走 Event Queue,優(yōu)先級和 Future 一模一樣,永遠(yuǎn)低于微任務(wù)。
4. 基礎(chǔ)案例: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
}
執(zhí)行順序
- 同步:A → E
- 微任務(wù):D
- Event 隊列(按加入順序):B → C
輸出
A
E
D
B
C
5. 進階:StreamController.add 執(zhí)行規(guī)則(面試最愛考)
import 'dart:async';
void main() {
print('1');
final sc = StreamController<int>();
sc.stream.listen((val) {
print('listen: $val'); // ?? Event 任務(wù)
});
print('2');
sc.add(100); // ?? 發(fā)射事件 → 入 Event Queue
Future.microtask(() => print('micro')); // ?? 微任務(wù)
print('3');
}
執(zhí)行順序
- 同步:1 → 2 → 3
- 微任務(wù):micro
- Event:listen: 100
輸出
1
2
3
micro
listen: 100
6. 地獄題級別:Stream + async/await + Future + Microtask(你文章風(fēng)格)
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. 直接插入你文章「萬能記憶口訣」的最終版
我?guī)湍阊a成終極完整版口訣:
- 同步優(yōu)先,全部跑完再處理異步;
- 微任務(wù)優(yōu)先級 > 事件任務(wù);
- 微任務(wù)一次性清空,事件任務(wù)一次執(zhí)行一個;
- Future本體是Event,then/await后續(xù)是Microtask;
- Stream 發(fā)射/監(jiān)聽 = Event,和 Future 同級;
- 執(zhí)行完一個Event,必清空一次Microtask;
- Timer 等同于普通Event任務(wù);
- Isolate 獨立隔離,不干擾主線程順序。
我?guī)湍憧偨Y(jié)成一句最精煉的(面試口述)
Stream 是異步事件流,所有發(fā)射和回調(diào)都走 Event Queue,執(zhí)行優(yōu)先級和 Future、Timer 完全一樣,永遠(yuǎn)低于微任務(wù)。listen 注冊是同步的,數(shù)據(jù)回調(diào)是異步的。
如果你愿意,我可以把 Stream 直接完美融入你整篇文章的結(jié)構(gòu)里,變成一篇完整、可直接發(fā)表、面試滿分的 Dart EventLoop 終極文章。
六、萬能記憶口訣(通殺所有順序題)
- 同步優(yōu)先,全部跑完再處理異步;
- 微任務(wù)優(yōu)先級 > 事件任務(wù);
- 微任務(wù)一次性清空,事件任務(wù)一次執(zhí)行一個;
- Future本體是Event,then/await后續(xù)是Microtask;
- 執(zhí)行完一個Event,必清空一次Microtask;
- Timer 等同于普通Event任務(wù);
- Isolate 獨立隔離,不干擾主線程順序。