为什么未来的序列以这种方式运行?

Why future sequence runs this way?

提问人:Deathchainer 提问时间:3/17/2023 最后编辑:TylerHDeathchainer 更新时间:11/15/2023 访问量:48

问:

以下代码:

void main() async {
  print("A");
  await Future(() async { // Main future
    print("B");
    Future(()=>print("C"));
    Future.microtask(()=>print("D"));
    await Future(()=>print("E"));
    print("F");
  });
  print("G");
}

显示以下序列:A B D C E F G

我期待这个序列:A B E F D C G

说明:

  1. 飞镖印刷品,正确A
  2. 在将来的飞镖印刷品中,正确B
  3. print(“C”) 进入 EventQueue,我们仍然在 EventLoop 中完成 Main Future Event
  4. print(“D”) 进入 MicrotaskQueue,我们仍然在 EventLoop 中完成 Main Future Event
  5. print(“E”) 打印,我们仍然需要等待 EventLoop 中的 Main Future 事件E
  6. print(“F”) 打印F
  7. 主未来完成,进入 MicrotaskQueue 并接受微任务,打印D
  8. 打印 EventQueue 中的下一个事件C
  9. 完成打印G

我的错误在哪里?Flutter 可以中断 Event completion 并将其发送回 Event 队列吗?为什么 D 和 C 在 E 之前完成?

DART 异步 序列 的未来

评论


答:

3赞 Luatic 3/17/2023 #1

感兴趣的只是身体:

Future(()=>print("C"));
Future.microtask(()=>print("D"));
await Future(()=>print("E"));
print("F");

您期待并在执行之前并执行以下说明:EFDC

  1. print(“E”) 打印 E,我们仍然需要等待 EventLoop 中的 Main Future 事件
  2. print(“F”) 打印 F
  3. 主 Future 完成,进入 MicrotaskQueue 并接受微任务,打印 D

Flutter 可以中断 Event completion 并将其发送回 Event 队列吗?

你在这里的假设是,“主要未来”不应该被打断。但是,当您在主将来中使用 await 时,您将控制权返回到事件循环。此时,微任务队列由 D 组成,而常规事件队列按此顺序由 C 和 E 组成。

首先执行微任务。所以是先执行的。 现在执行常规任务。 被执行。 现在被执行。控制权被转移回“主要未来”,即 .主要的未来继续。DCEawaitEprintF

3赞 lrn 3/17/2023 #2

以下是对何时发生的情况以及原因的完整说明:

void main() async {
  print("A");
  await Future(() async { // Main future
    print("B");
    Future(()=>print("C"));
    Future.microtask(()=>print("D"));
    await Future(()=>print("E"));
    print("F");
  });
  print("G");
}
  • main由事件循环调用。
  • main所以这创造了一个未来的 F0。async
  • print("A")运行并打印“A”。
  • Future(() async { // Main future ... })被评估
  • 这创造了一个新的未来F1
  • 它启动一个持续时间为零的计时器 T1 来运行该函数。
  • on F1 退出调用,返回 F0。awaitmain
  • 控制返回到事件循环。
  • 上面的计时器 T1 将构造函数代码作为新事件触发。Future()
  • 它从上面运行功能。
  • 它是一个异步函数,因此它会创建未来的 F2。
  • 它打印“B”。
  • 创建要运行的 Future F3 和零持续时间计时器 T2。Future(() => print("C"))() => print("C")
  • 创建一个 Future F4 并计划一个微任务 M1 来运行。Future.microtask(...)() => print("D")
  • 创建要运行的 Future F5 和 zerp 持续时间计时器 T3 。Future(()=>print("E"))() => print("E")
  • 在 F5 上退出返回 F2 的内部函数。await
  • Future F1 与尚未完成的未来 F2 一起完成/链接。
  • 微任务 M1 触发,运行功能打印“D”。F4 以 完成。没人听。null
  • 微任务队列为空
  • 定时器 T2 触发器。
  • 这将打印“C”并使用 完成 F3。没人听。null
  • 定时器 T3 触发器。
  • 打印“E”并使用 null 完成 F5。
  • F5 上的等待完成。
  • 内部函数打印“F”。
  • 内部函数返回,用 完成 F2。null
  • 这样就完成了 F1。null
  • 在 F1 上完成。await
  • main打印“G”并返回,用 完成 F0。没人听。null