内容简介:接触过Flutter的人都知道,Flutter是用Dart来写的,Dart没有进程和线程的概念,所有的Dart代码都是在isolate上运行的,那么isolate到底是什么?本系列的文章将详细讨论。这篇文章讨论事件队列(event loop)及Dart代码运行顺序。我们对Dart代码进行分类:同步代码和异步代码; 我们在写Dart代码的时候,就只有两种代码,这两类代码是不同的:
接触过Flutter的人都知道,Flutter是用Dart来写的,Dart没有进程和线程的概念,所有的Dart代码都是在isolate上运行的,那么isolate到底是什么?本系列的文章将详细讨论。这篇文章讨论事件队列(event loop)及Dart代码运行顺序。
0x00 同步代码和异步代码
我们对Dart代码进行分类:同步代码和异步代码; 我们在写Dart代码的时候,就只有两种代码,
- 同步代码:就是一行行写下来的代码
- 异步代码:就是以Future等修饰的代码
这两类代码是不同的:
1.运行顺序不同
同步代码和异步代码运行的顺序是不同的:
先运行同步代码,在运行异步代码 复制代码
就是,即使我异步代码写在最前面,同步代码写在最后面,不好意思,我也是先运行后面的同步代码,同步代码都运行完后,在运行前面的异步代码。
2.运行的机制不同
异步代码是运行在 event loop
里的,这是一个很重要的概念,这里可以理解成Android里的Looper机制,是一个死循环, event loop
不断的从事件队列里取事件然后运行。
0x01 event loop 架构
下面是event loop大致的运行图:
这个很好理解,事件events加到Event queue里,Event loop循环从Event queue里取Event执行。
这个理解后,在看event loop详细的运行图:
从这里看到,启动app(start app)后:
- 先查看MicroTask queue是不是空的,不是的话,先运行microtask
- Microtask queue空了之后,在判断Event queue是不是空的,不是的话,运行event
- Event queue空了之后,在继续第1步
这里多了两个名词: MicroTask
和 Event
,这代表了两个不同的异步task
1. MicroTask
这个大家应该不太清楚,但是这个也是 dart:async
提供的异步方法,使用方式:
// Adds a task to the 先查看MicroTask queue. scheduleMicrotask((){ // ...code goes here... }); 复制代码
2.Event
Event我们就很清楚了,就是Future修饰的异步方法,使用方式:
// Adds a task to the Event queue. new Future(() { // ...code goes here... }); 复制代码
0x02
纯粹讲理论知识不太好理解,我们直接上代码,讲一个例子,看如下的代码,请问打印顺序是什么样的?
import 'dart:async'; void main() { print('main #1 of 2'); scheduleMicrotask(() => print('microtask #1 of 3')); new Future.delayed(new Duration(seconds:1), () => print('future #1 (delayed)')); new Future(() => print('future #2 of 4')) .then((_) => print('future #2a')) .then((_) { print('future #2b'); scheduleMicrotask(() => print('microtask #0 (from future #2b)')); }) .then((_) => print('future #2c')); scheduleMicrotask(() => print('microtask #2 of 3')); new Future(() => print('future #3 of 4')) .then((_) => new Future( () => print('future #3a (a new future)'))) .then((_) => print('future #3b')); new Future(() => print('future #4 of 4')); scheduleMicrotask(() => print('microtask #3 of 3')); print('main #2 of 2'); } 复制代码
-
首先运行同步代码
所以是:
main #1 of 2 main #2 of 2 复制代码
-
接下来是异步代码
Dart的异步队列不是我们平常想的那样,一边往队列里加task,一边运行,而是先往队列里添加task,所有task添加完毕,才会运行,所以
Future
的task就添加到event queue
,而scheduleMicrotask
添加到microtask queue
。 -
microtask queue
这里就是:
microtask #1 of 3 microtask #2 of 3 复制代码
-
event queue event queue还有有特殊的情况需要考虑:
-
Future.delayed
需要延迟执行的,Dart是怎么执行的呢,是在延迟时间到了之后才将此task加到
event queue
的队尾,所以万一前面有很耗时的任务,那么你的延迟task不一定能准时运行 -
Future.then
Future.then里的task是不会加入到
event queue
里的,而是当前面的Future执行完后立即掉起,所以你如果想保证异步task的执行顺序一定要用then,否则Dart不保证task的执行顺序这里就是:
future #2 of 4 future #2a future #2b future #2c future #3 of 4 future #4 of 4 microtask #0 (from future #2b) future #3a (a new future) future #3b future #1 (delayed) 复制代码
-
这里你肯定好奇为啥 future #4 of 4
在 future #3 of 4
后面,因为 future #3 of 4
的then里又新建了一个Future,所以这个task会加到 event queue
的最后面。
最后的结果就是:
main #1 of 2 main #2 of 2 microtask #1 of 3 microtask #2 of 3 microtask #3 of 3 future #2 of 4 future #2a future #2b future #2c future #3 of 4 future #4 of 4 microtask #0 (from future #2b) future #3a (a new future) future #3b future #1 (delayed) 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 顺序、条件、循环语句的底层解释
- Spring中循环依赖的正确性与Bean注入的顺序关系
- ViewGroup 默认顺序绘制子 View,如何修改?什么场景需要修改绘制顺序?
- JavaScript万物产生顺序
- SpringBoot配置加载顺序
- SQL语句执行顺序详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。