8

我想了解飞镖事件循环是如何工作的。我从The Event Loop and Dart网站上阅读了事件循环文章,作者很好地解释了 dart 中的事件循环是如何工作的。

但我不明白的是,事件如何排队。例如

new Future(() => 21)
    .then((v) => v*2)
    .then((v) => print(v));

dart 会在事件队列中创建三个条目还是只创建一个?我知道,Future 类负责延迟执行,当我从它创建一个对象时

new Future(() => 21)

它只是事件循环中的一项。

在我上面提到的这篇文章中,我读到了微任务。这个微任务要在事件队列之前执行,但是我看不出有什么意义,为什么飞镖团队要实现这个微任务?也许我需要一些例子!

4

4 回答 4

6

当你这样做时:

new Future(() => 21)
.then((v) => v*2)
.then(print);
  • 首先调用new Future(...)构造函数。这将创建一个 Future 对象并安排一个Timer来执行您作为参数提供的函数。
  • 然后你打电话then。这会创建一个新的未来(称为future#2)并在第一个未来上添加一个监听器。没有安排任何活动。
  • 然后你then再打电话。这将创建另一个未来(future#3)并在 future#2 上添加一个监听器。没有安排任何活动。
  • 然后定时器触发,()=>21执行,第一个future完成,值为21。
  • 然后立即执行第一个未来的侦听器。用 21调用(v)=>v*2,然后用值 42 完成 future#2。
  • future#2 上的监听器然后立即执行。调用print42,打印 42 并返回null。这用 value 完成了 future#3 null

未来完成目前是通过“传播”函数完成的,该函数试图完成尽可能多的未来,只要它们的侦听器是同步的。这就是为什么完成一个未来会立即完成另一个未来,而无需任何中间微任务。

于 2014-06-04T18:56:41.513 回答
6

经过一番调查,似乎正确的答案是“它们将在下一个事件循环中执行”

要对其进行测试,您可以编写如下内容:

import "dart:async";
void main() {
  new Future(() {
    scheduleMicrotask(()=>print("before loop 1"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(()=>print("before loop 2"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(()=>print("before loop 3"));
    print("in event loop");
  });
}

它应该输出:

在事件循环
中 在事件循环
中 在事件循环中
在循环 1
之前 在循环 2
之前 在循环 3 之前

虽然我不确定你不能打破这个优化。所以唯一确定的事实是第一个Future将首先完成,第二个 - 第二个。

编辑:奇怪的部分(过时):

使用这样的代码:

import "dart:async";
void main() {
  new Future(() {
    scheduleMicrotask(print("before loop 1"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(print("before loop 2"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(print("before loop 3"));
    print("in event loop");
  });
}

输出是:

before loop 1
in event loop
before loop 2
in event loop
before loop 3
in event loop
Unhandled exception:
The null object does not have a method 'call'.

NoSuchMethodError: method not found: 'call'
Receiver: null
...

但是有了这个:

import "dart:async";
void main() {
  new Future(() {
    scheduleMicrotask(()=>print("before loop 1"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(()=>print("before loop 2"));
    print("in event loop");
  }).then((_) {
    scheduleMicrotask(()=>print("before loop 3"));
    print("in event loop");
  });
}

输出是:

在事件循环
中 在事件循环
中 在事件循环中
在循环 1
之前 在循环 2
之前 在循环 3 之前

编辑2:

我想我明白了。在第一个(错误的版本)中scheduleMicrotask ,实际上从未正确安排过,但由于 Dart 有急切的参数执行,它print()无论如何都会执行。所以发生的事情是所有Future在下一个事件循环中执行并打印所有文本。这就是输出按调用顺序排列的原因:

事件循环中的循环 1之前
事件循环中的
循环 2之前
事件循环 中的
循环 3 之前

而不是按计划顺序。

于 2014-06-04T10:50:54.090 回答
1

微任务队列是对异步执行进行排队,但避免在这些微任务完成之前返回主事件循环。即使在执行主队列中排队的其他异步任务/事件之前异步执行,您也可以确保完全完成某些相关活动。

似乎从thenlike执行的代码(v) => v*2再次在 a 内部执行,Future因为then总是返回 a Future

来自https://www.dartlang.org/articles/event-loop/

微任务队列是必要的,因为事件处理代码有时需要稍后完成任务,但在将控制权返回给事件循环之前。例如,当一个可观察对象发生变化时,它将几个突变变化组合在一起并异步报告它们。微任务队列允许可观察对象在 DOM 显示不一致状态之前报告这些突变变化。

我如何解释此描述与@Jare 答案中的测试结果不符。

于 2014-06-04T06:22:37.273 回答
1

只是要添加到以前的答案中。“事件循环”文章很好地解释了这种行为:

当 Future 完成时,您传递给 Future 的 then() 方法的函数会立即执行。(该函数没有入队,它只是被调用。)

https://www.dartlang.org/articles/event-loop/

这意味着在上面的示例中,总是有一个事件,但有许多微任务。

于 2015-08-12T18:09:26.353 回答