Dart 事件循环:理解为什么这样的顺序打印(案例 4)

问题描述 投票:0回答:2

有以下代码:

案例1.基本示例

Future<void> main() async {
 print('A');

  await Future(
    () {
      print('C');
      Future(() => print('D'));
      Future(() => print('E')).then((value) => print('F'));
      Future.microtask(() => print('W'));
      Future.microtask(() => print('Z'));
      print('G');
    },
  );

  print('B');
}

输出:A C G B W Z D E F

  1. “A”将首先出现在屏幕上,因为这是按顺序执行的同步操作。
  2. 接下来,Future 带有await 关键字(第4 行),这意味着我们将控制权转移到Future 内的函数范围(第5 - 12 行)。标有await 的函数下面的代码将不会执行,直到该函数返回一些结果。
  3. 在 Future 中(第 4 行),我们看到输出“C”,然后是四个带有其他字母输出的 Future 和输出“G”。
  4. “C”将首先输出,因为这是同步操作。
  5. Futures(第 7 - 10 行)被安排用于事件循环的下一次迭代,因为我们没有使用 wait 关键字来标记它们。
  6. 接下来,将显示“G”。
  7. 第4行Future内部的函数返回了结果,所以控制返回到主函数,剩下输出“B”,执行成功。
  8. 主函数结束后,事件循环的下一次迭代开始,首先检查微任务队列,然后检查事件队列。
  9. 在事件循环的上一次迭代中,调度了微任务(第 9、10 行),微任务按照调度的顺序成功执行,并会显示“W”和“Z”。
  10. 接下来,事件队列开始清空,其中有来自Future的函数(第7、8行)。 Future(第 8 行)还有一个“then”回调,将在 Future 成功时执行。因此,将显示字母 D E F。

案例2

Future<void> main() async {
 print('A');

  await Future(
    () async {
      print('C');
      Future(() => print('D'));
      await Future(() => print('E')).then((value) => print('F'));
      Future.microtask(() => print('W'));
      Future.microtask(() => print('Z'));
      print('G');
    },
  );

  print('B');
}

输出:A C D E F G B W Z

  1. 字母“DEF”已从末尾移至中间。发生这种情况是因为await关键字自动将我们重定向到事件循环的新迭代,其中Future已经调度(第7行),并且我们还将控制权转移到Future中的函数范围(第8行),因此代码在函数返回结果之前,下面的代码不会被执行。

  2. 执行后,代码将像基本示例一样继续运行。

案例3

Future<void> main() async {
 print('A');

  await Future(
    () async {
      print('C');
      Future(() => print('D'));
      Future(() => print('E')).then((value) => print('F'));
      Future.microtask(() => print('W'));
      await Future.microtask(() => print('Z'));
      print('G');
    },
  );

  print('B');
}

输出:A C W Z G B D E F

  1. Await 自动跳转到事件循环的下一次迭代,并将控制权传递给我们想要等待的函数的范围,直到它返回结果。
  2. 事件循环在第 10 行看到“await”,并开始按照计划的顺序执行微任务队列,并执行“Z”微任务,将控制返回到上面的范围,因为函数返回了结果。
  3. 事件循环在迭代时没有时间到达事件队列并清除微任务队列,因此事件将保留到事件循环的下一次迭代(将在执行 main 方法后开始)。

案例4

Future<void> main() async {
 print('A');

  await Future(
    () async {
      print('C');
      Future(() => print('D'));
      Future(() => print('E')).then((value) => print('F'));
      Future.microtask(() => print('W'));
      Future.microtask(() => print('Z'));
      print('G');
    },
  );

  print('B');
}

输出:A C G W Z B D E F

微任务显示在输出“B”之前。

这个案例没看懂。

flutter dart asynchronous event-loop dart-isolates
2个回答
1
投票

由于

await
只是调用
Future.then
的语法简写,因此您可以将 Case 4 替换为以下内容:

void main() async {
 print('A');

 Future(
   () async {
     print('C');
     Future(() => print('D'));
     Future(() => print('E')).then((value) => print('F'));
     Future.microtask(() => print('W'));
     Future.microtask(() => print('Z'));
     print('G');
   },
 ).then((_) => print('B'));
}

并且根据docs,如果 future 已经完成,回调将不会立即调用,而是会安排在稍后的微任务中。 因此

print('B')
将作为微任务添加到已包含
print('W')
print('Z')
微任务的微任务队列中。

我的答案基于以下讨论,阅读起来非常有用。


0
投票

我真的很喜欢你对案例 1-3 的解释。我可以肯定地告诉你,事件循环行为最让我惊讶。

不幸的是,我从未听说过看到

await
事件循环被重定向到新的迭代,您能否提供我可以在哪里进一步了解它?

另外,我对第三个案例和案例中的第三点很感兴趣。

The event loop does not have time to reach the event queue at the iteration
。这是对所发生情况的有趣解释,但我找不到有关流程的更多信息。是否有可能应用文档链接或其他内容来更深入地调查此类行为?

先谢谢你了。再说一遍,这是一张很棒的票

© www.soinside.com 2019 - 2024. All rights reserved.