FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
  • 内功心法

    • 《深入浅出设计模式Java版》笔记
前端
后端
  • 产品
  • 代理
  • 提效
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
  • 内功心法

    • 《深入浅出设计模式Java版》笔记
前端
后端
  • 产品
  • 代理
  • 提效
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • AndroidUI

  • Android第三方SDK

  • Android混淆

  • Android仓库

  • Android新闻

  • Android系统开发

  • Android源码

  • Android注解AOP

  • Android脚本

  • AndroidTv开发

  • AndroidNDK

  • Android音视频

  • Android热修复

  • Android性能优化

  • Android云游戏

  • Android插件化

  • iOSUI

  • iOS工具

  • iOS底层原理与应用

  • iOS组件化

  • iOS音视频

  • iOS疑难杂症

  • iOS之Swift

  • iOS之RxSwift

  • iOS开源项目

  • iOS逆向

  • Flutter开发

    • Dart - 抽象类的实例化
    • Flutter - 打印好用的Debug日志
    • Flutter - 混合开发
    • Flutter - 解决混合开发iOS脚本打包遇到的问题
    • Flutter - 低版本在iOS14上遇到的问题与解决方案
    • Flutter - 解决原生弹窗的触摸事件被Flutter响应的问题
    • Flutter - 实现列表上下拉切换header
    • Flutter - 获取ListView当前正在显示的Widget信息
    • Flutter - 列表滚动定位超强辅助库,墙裂推荐!🔥
    • Flutter - 快速实现聊天会话列表的效果,完美💯
    • Flutter - 聊天输入框更新文本时的必备优化点🔖
    • Flutter - 我给官方提PR,解决run命令卡住问题 😃
    • Flutter - 探索run命令到底做了什么 🤔
    • Flutter - 引擎调试(iOS篇)🛠
    • Flutter - 引擎调试bug到提交PR实战 🐞
    • Flutter - 船新升级😱支持观察第三方构建的滚动视图💪
    • Flutter - 瀑布流交替播放视频 🎞
    • Flutter - IM保持消息位置大升级(支持ChatGPT生成式消息) 🤖
    • Flutter - 滚动视图中的表单防遮挡 🗒
    • Flutter - 秒杀1/2曝光统计 📊
    • 一天内加入 Flutter 和 FlutterCandies 两大组织是什么体验 🧐
    • Flutter - 如何快速搓一个微信通讯录列表(azlist) 📓
    • Flutter - 混编项目集成Shorebird热更新🐦(安卓篇)
    • Flutter - 混编项目集成Shorebird热更新🐦(iOS篇)
    • Flutter - 解决返回原生页面时dispose方法未被触发的问题 🐞
    • Flutter - 升级3.19之后页面多次rebuild?🤨
    • Flutter - 热更新 Shorebird 1.0 正式版来了 🐦
    • Flutter - 使用Pigeon实现视频缓存插件 🐌
    • Flutter - 轻松搞定屏幕旋转功能 😎
    • Flutter - 解决Connection closed before full header was received
    • Flutter - 实现聊天键盘与功能面板的丝滑切换 🍻
    • Flutter - 支持观察NestedScrollView,兼容性更强 😈
    • Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻
    • Flutter - 升级到3.24后页面还会多次rebuild吗?🧐
    • Flutter - 轻松实现PageView卡片偏移效果
    • Flutter - 轻松搞定炫酷视差(Parallax)效果
    • Flutter - 危!3.24版本苹果审核被拒!
    • Flutter - 子部件任意位置观察滚动数据
    • Flutter - iOS编译加速
    • Flutter - Xcode16 还原编译速度
    • Flutter - GetX Helper 助你规范应用 tag
    • Flutter - GetX Helper 如何应用于旧页面
    • Flutter - 聊天面板库动画生硬?这次让你丝滑个够
    • Flutter - 使用本地 DevTools 验证 SVG 加载优化
    • Flutter - 详情页 TabBar 与模块联动?秒了!
    • Flutter - 详情页初始锚点与优化
    • Flutter - Melos Pub workspaces 实践
    • Flutter webview 崩溃率上升怎么办?我的分析与解决方案
    • Flutter 多仓库本地 Monorepo 方案与体验优化
    • Flutter 拖拉对比组件,换装图片前后对比必备
    • Flutter 3.44 插件内置 Kotlin (KGP) 双向兼容适配指南
    • Flutter 无障碍开发实战:玩转 Semantics 解决视障用户使用痛点
    • 玩转 WebSocket:从原理到 Flutter 实战
    • 别在 Flutter 的 main() 里乱锁屏幕方向,小心 iPad 分屏功能被你搞没了
    • Flutter 3.44 性能飞跃:深度解析 Android Platform View 的 HCPP 新特性
    • 给 Flutter 插件加上 Swift Package Manager 支持
    • 彻底搞懂 Dart Stream:从底层原理到 Flutter 实战与面试题集
    • 别被“Flutter 传感器延迟 150ms”带偏了:这可能只是你的实现方式错了
    • StatefulWidget 里的隐形炸弹:为什么不要在 State 类中使用 context.mounted
    • 深入理解 Flutter 架构:从 Widget 到 GPU 像素的全链路解析
    • 深度拆解 Dart 事件循环:从面试题看清 Microtask 与 Event Queue 的执行顺序
      • 一、一个能测出水平的面试题
      • 二、重新理解 Dart 的单线程模型
      • 三、手把手拆解执行顺序
        • 进阶挑战:嵌套任务的逻辑
      • 四、深入 async/await 与 scheduleMicrotask
        • 1. async/await 的本质:状态机
        • 2. scheduleMicrotask 与 Future.microtask
      • 五、实战避坑:别让你的 UI 卡死
        • 1. 糟糕的写法:阻塞主线程
        • 2. 优雅的方案:利用 Isolate
        • 3. 微任务饥饿(Microtask Starvation)
      • 六、总结:面试官到底在考什么
    • Flutter FocusNode 实战指南:玩转键盘焦点与用户输入体验
    • iOS 27 强制要求 UISceneDelegate:UIKit 和 Flutter 开发者该如何应对?
    • Flutter 实战:为你的 App 增加桌面快捷方式 (Quick Actions)
    • 玩转 Flutter 项目依赖:从 pubspec.yaml 到实战包管理
  • 移动端
  • Flutter开发
GitLqr
2026-08-02
目录

深度拆解 Dart 事件循环:从面试题看清 Microtask 与 Event Queue 的执行顺序

欢迎关注微信公众号:[FSA全栈行动 👋]

# 一、一个能测出水平的面试题

很多 Flutter 开发者天天在写 async/await,感觉上手很顺,但真要是碰到面试官抛出一个关于执行顺序的问题,估计不少人得懵。

假设面试官在白板上给你写下这么一段代码:

import 'dart:async';

void main() {
  print('A');
  Future(() => print('B'));
  Future.microtask(() => print('C'));
  print('D');
}

面试官会问你: “A、B、C、D 的输出顺序是什么?为什么?Event Queue 和 Microtask Queue 有什么区别?scheduleMicrotask 是干嘛的?既然 Dart 是单线程的,它是怎么处理成千上万个并发任务的?”

大多数人的第一直觉可能是 A, B, C, D 或者 A, D, B, C。

但真正的答案是 A, D, C, B。

想要解释清楚这个顺序,你得彻底搞懂 Dart 的异步模型。

# 二、重新理解 Dart 的单线程模型

Dart 的运行是在一个叫 Isolate 的隔离体中进行的。在同一个 Isolate 内部,它是单线程执行的。所谓的“并发”,本质上是依靠 Event Loop(事件循环)来不停地调度任务。

它的工作逻辑其实非常机械化:

  1. 执行当前的同步代码(Synchronous code)。

  2. 检查 Microtask Queue,如果里面有东西,一次性全部清空。

  3. 从 Event Queue 中取出一个任务执行。

  4. 回到步骤 2,循环往复。

这里最关键的认知偏差就在于:Microtask Queue 的优先级高于 Event Queue。

我们可以通过下表直观对比一下这两个队列:

维度 Microtask Queue Event Queue
优先级 极高。在处理下一个事件前,必须清空当前所有微任务 常规。每次循环只处理一个事件
包含内容 Future.microtask、scheduleMicrotask、.then 回调 Future、Timer、Stream 事件、I/O 完成回调
调度逻辑 一旦进入,直到队列为空才停 一个一个来,处理完一个会去检查一次微任务

# 三、手把手拆解执行顺序

让我们回到刚才那个面试题,一步步拆解 main 函数的执行过程:

import 'dart:async';

void main() {
  print('A'); // ① 同步代码,立即执行
  Future(() => print('B')); // ③ 放入 Event Queue
  Future.microtask(() => print('C')); // ② 放入 Microtask Queue
  print('D'); // ① 同步代码,立即执行
}

拆解流程如下:

  1. main() 函数启动,进入同步执行阶段。

  2. print('A') 执行 $\to$ 输出 A。

  3. Future(() => ...) 被调用,B 被丢进了 Event Queue 等着。

  4. Future.microtask(() => ...) 被调用,C 被丢进了 Microtask Queue。

  5. print('D') 执行 $\to$ 输出 D。

  6. 同步代码执行完毕,main() 准备返回。

  7. 事件循环介入:检查 Microtask Queue,发现 C 在里面,立即执行 $\to$ 输出 C。

  8. Microtask Queue 空了,轮到 Event Queue。发现 B 在里面,执行 $\to$ 输出 B。

最终输出:A, D, C, B

# 进阶挑战:嵌套任务的逻辑

如果任务嵌套了,情况会变得更有意思:

import 'dart:async';

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

  Future.delayed(Duration.zero, () => print('2 event (delayed)'));

  Future.microtask(() {
    print('3 microtask');
    Future.microtask(() => print('4 nested microtask'));
  });

  Future(() {
    print('5 event');
    Future.microtask(() => print('6 microtask inside event'));
  });

  scheduleMicrotask(() => print('7 scheduleMicrotask'));

  print('8 sync end');
}

输出结果:

1 sync
8 sync end
3 microtask
7 scheduleMicrotask
4 nested microtask
2 event (delayed)
5 event
6 microtask inside event

这里有几个核心逻辑需要拿捏:

  • 同步优先:1 和 8 是同步任务,必须先跑完。

  • 微任务“死磕到底”:3 执行时又塞进了一个 4。注意!4 会被排在 7 后面,但由于 Event Loop 会一直清空微任务队列,所以 3、7、4 会在任何 Event(如 2 或 5)出现之前全部跑完。

  • Future.delayed(Duration.zero) ≠ 微任务:它本质上是往 Event Queue 里塞了一个任务,所以它得排在微任务后面。

# 四、深入 async/await 与 scheduleMicrotask

# 1. async/await 的本质:状态机

很多人觉得 await 是让线程“停下来等结果”,其实不对。Dart 编译 async 函数时,会把它转成一个状态机。

当你 await 一个 Future 时,函数会在这里“挂起”,把控制权还给 Event Loop。等 Future 结果出来了,Event Loop 再通过一个微任务把刚才挂起的地方“唤醒”。

这就解释了为什么 await 不会阻塞 UI。

# 2. scheduleMicrotask 与 Future.microtask

这两者都是往 Microtask Queue 里塞任务,但有个小区别:

  • Future.microtask 返回一个 Future,你可以用 await 去等它的结果。

  • scheduleMicrotask 返回 void,它就是“发射后不管”(fire-and-forget)。

避坑指南: Future.value(x).then(callback) 里的 callback 是直接进 Microtask Queue 的;而普通的 Future(() => ...) 则是先进 Event Queue。

# 五、实战避坑:别让你的 UI 卡死

既然 Dart 是单线程的,如果我们在主线程(Isolate)里跑一个耗时极长的同步循环,Event Loop 就没法去处理 Timer、I/O 或者 UI 渲染请求了,表现出来的现象就是 Flutter 界面直接卡死(Jank)。

# 1. 糟糕的写法:阻塞主线程

int heavySync() {
  int sum = 0;
  for (int i = 0; i < 100000000; i++) {
    sum += i;
  }
  return sum;
}

# 2. 优雅的方案:利用 Isolate

对于纯计算密集型任务,不要在 Isolate 内部死磕,直接开一个新的 Isolate。在现代 Dart 中,推荐使用 Isolate.run(),它非常简洁。

// ✅ 最优解:直接扔给新的 Isolate
Future<int> heavyInIsolate() async {
  return await Isolate.run(() {
    int sum = 0;
    for (int i = 0; i < 100000000; i++) {
      sum += i;
    }
    return sum;
  });
}

# 3. 微任务饥饿(Microtask Starvation)

这是一种比较隐蔽的 Bug。如果你在微任务里不停地 scheduleMicrotask,导致 Microtask Queue 永远填不满,那么 Event Loop 就会永远卡在“清空微任务”这一步,永远轮不到 Event Queue。

后果: Timer 不触发、Stream 不回调、UI 刷新停滞。

# 六、总结:面试官到底在考什么

面试官问这些,不是为了让你背出 A, D, C, B,而是看你对 “异步非阻塞” 的底层认知。

记下这些核心点,面试稳过:

  1. 执行优先级:同步代码 $\to$ 微任务队列(彻底清空)$\to$ 事件队列(一个一个来)。

  2. 单线程并发:Dart 通过 Event Loop 实现并发。I/O 等耗时操作交给系统底层处理,系统完成后通过 Event Queue 发送通知,Dart 只负责执行回调。

  3. async/await 本质:是状态机。await 会挂起当前函数并释放控制权,而不是阻塞线程。

  4. 计算密集型任务:必须交给 Isolate,否则会由于阻塞 Event Loop 导致 UI 掉帧。

一句话口诀: 同步先跑,微任务清空,事件轮转。

#async#await#Isolate#Microtask Queue#Event Queue#Event Loop
上次更新: 2026/08/09, 04:29:06
深入理解 Flutter 架构:从 Widget 到 GPU 像素的全链路解析
Flutter FocusNode 实战指南:玩转键盘焦点与用户输入体验

← 深入理解 Flutter 架构:从 Widget 到 GPU 像素的全链路解析 Flutter FocusNode 实战指南:玩转键盘焦点与用户输入体验→

最近更新
01
玩转 Flutter 项目依赖:从 pubspec.yaml 到实战包管理
08-08
02
Flutter 实战:为你的 App 增加桌面快捷方式 (Quick Actions)
08-07
03
iOS 27 强制要求 UISceneDelegate:UIKit 和 Flutter 开发者该如何应对?
08-06
更多文章>
Theme by Vdoing | Copyright © 2020-2026 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×