Dart 里的“任务”并不只是一个抽象概念,它直接关系到代码为什么会先执行这里、后执行那里。本文从任务的定义出发,梳理同步任务与异步任务的区别,再把微任务、事件任务以及异步状态串起来,帮助你建立一套更接近运行机制的理解框架,也能在读代码时更容易判断执行顺序。
什么是 Dart 里的任务
理解 Dart 任务,先要把“任务”这个词放回更一般的语境里看。无论在生活中、计算机中还是 Dart 程序里,任务都可以理解为一项被安排去完成的具体工作,只是执行者和调度方式不同。
- 生活中的任务:指派给个人或团队的特定工作,也可以是自己主动安排的事项,比如当天要完成多少配送单。
- 计算机中的任务:由操作系统调度器管理的逻辑工作单元,执行依托线程或进程资源,例如数据处理、网络请求。
- Dart 中的任务:程序为了达成某个目标而执行的具体操作,例如发起请求、读取文件等,这些工作最终都需要通过 Dart 的执行机制来调度。
把这三类定义放在一起看,会更容易抓住 Dart 任务的几个共性。
任务有哪些共同特征
1. 任务会消耗资源。
生活中的任务要耗费人力、时间或工具;计算机中的任务要占用进程、线程、内存或 I/O;Dart 中的任务也不例外,执行时同样会使用运行时资源。
2. 任务可以并行,也可以并发。
生活里“一边吃饭一边追剧”更像并行,“吃一会儿、看一会儿”更接近并发。计算机中多个线程或进程可并行处理任务,而单线程环境下则通常通过交错推进形成并发。Dart 更常见的是依靠事件循环和任务队列来安排这种交错执行。
3. 任务具有状态。
任务不是从开始直接跳到结束,它会经历准备、执行、等待、完成等不同阶段。这个特点在操作系统里很典型,在 Dart 的异步任务里也同样存在。
4. 任务具有明确目标。
任务之所以存在,是为了完成某个结果。对 Dart 而言,这个结果可能是拿到网络响应、完成文件读取,或者推进一段逻辑执行完毕。
Dart 任务如何分类
如果按照执行方式来分,Dart 中的任务可以先归为两类:同步任务和异步任务。这也是理解执行顺序的第一层入口。
同步任务为什么总是按顺序执行
同步任务的特点是:前一个没做完,后一个就不能开始。它的执行方式很像排队,必须一个接一个往下走。
看下面这段代码:
void main() {
print('任务1'); // 同步代码,最先开始执行,意味着最先打印这行。
print('任务2');
for(int i = 0; i < 100000; i++){} // 需要耗费时间的同步代码
print('任务3'); // 需要等待前面的同步代码执行完才能执行。
print('任务4');
}
输出:
任务1
任务2
任务3
任务4
这里的关键不在于 for 循环做了多复杂的事,而在于它仍然属于同步代码。只要循环没有跑完,后面的 print('任务3') 就不会开始执行。因此输出顺序严格固定,不会被打乱。
这也是初学者最容易先建立的一个判断:Dart 中同步任务会优先执行,而且必须顺序完成。
异步任务是如何让程序不被卡住的
如果所有操作都按同步方式排队,那一旦遇到网络请求、文件读写这类耗时工作,后面的逻辑就只能一直等。异步任务的意义,就是把“等待结果”这件事从主执行流程里拆出去。
可以把它理解成:任务先被发出去,主流程不必原地阻塞,等结果回来后,再根据状态继续处理。也正因为这样,异步任务通常对应的都是网络请求、I/O 操作或其他耗时过程。
在 Dart 中,异步任务还会继续细分为两类:
- 微任务:优先级更高的异步任务。
- 事件任务:由外部事件触发的异步任务,例如网络响应;它的优先级低于微任务。
因此,执行顺序并不是简单的“异步一起跑”,而是要继续看它到底进入了哪个队列。对理解事件循环来说,这一步很重要:同步任务先执行,异步任务再按队列规则调度,而异步内部又是微任务优先于事件任务。
异步任务的状态是怎样流转的
要看懂 Dart 异步任务的状态,可以先借助操作系统中的任务状态做一个参照。两者不是一一等同,但这种对照能帮助理解“任务并不是瞬间完成”的过程。
先看操作系统中的任务状态
- 创建:操作系统已经为任务分配资源,但还没准备好执行。
- 就绪:资源已经齐备,只等待 CPU 调度。
- 运行:任务正在 CPU 上执行指令。
- 阻塞:执行过程中因为等待某些事件而暂停,比如等待 I/O 完成。
- 终止:任务已经成功结束或失败结束,资源随后会被回收。
这套状态模型说明了一件事:任务的运行过程本身就是阶段性的,调度系统要处理的不只是“做或不做”,还包括“做到哪一步”。
在 Dart 里可以怎样理解异步状态
对应到 Dart 异步任务,原文给出了这样一组状态划分:
- 创建(created):任务被创建。
- 待定(pending):任务已经开始推进,但还没有完成。
- 执行(running):异步操作正在执行。
- 完成(completed):任务结束,可能是成功完成,也可能是失败完成。
- 清理(dispose):释放资源。
从理解角度看,这几个状态可以串成一条更直观的线:任务先被创建,然后进入处理中,实际执行完成后得到结果,最后再做资源清理。即便代码层面你看到的可能只是一个异步调用和一个回调,但在运行机制里,它经历的是一整段状态变化,而不是一次瞬时动作。
这也是为什么在分析 Dart 异步问题时,不能只盯着“有没有返回值”,还要看任务当前处在创建、等待、执行还是完成阶段。很多看似“没执行”或“顺序不对”的问题,本质上都是对任务状态和调度顺序理解不够清楚。
如何用一个框架理解执行顺序
把前面的内容合在一起,可以得到一个更适合实际阅读代码的判断框架。
第一步,先看当前代码是不是同步任务。只要是同步代码,它通常就会直接进入当前执行流程,并且优先完成。
第二步,如果是异步任务,再看它属于哪一类。微任务优先级高于事件任务,因此两个异步操作并不一定按照“谁先写谁先执行”的直觉来运行。
第三步,遇到结果延迟、顺序异常或者回调晚到时,再结合任务状态来分析。它可能不是没执行,而是还处在待定或执行阶段,也可能已经完成但尚未进入后续处理逻辑。
用这套方式看 Dart 任务,会比单纯记忆“同步、异步、微任务、事件任务”四个名词更有用,因为它能直接转化为判断执行顺序的思路。
总结
Dart 中的任务,本质上是为了完成某个程序目标而被调度执行的具体工作。按执行方式看,它可以分为同步任务和异步任务;其中同步任务顺序执行,异步任务则依靠事件循环和任务队列推进,而异步内部又要区分微任务与事件任务的优先级。
进一步看,异步任务并不是“发出去就结束了”,它还会经历创建、待定、执行、完成、清理等阶段。把定义、分类和状态这三部分连起来,理解 Dart 执行顺序时就会更清楚:先判断是不是同步,再判断异步进入哪个队列,最后结合状态去分析它为什么现在才执行、为什么结果还没回来。











