Dart事件队列和微任务

时间:2014-06-04 06:13:12

标签: dart event-loop dart-async

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

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

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

这里会不会在事件队列中创建三个条目或只创建一个条目?我知道,类Future负责延迟执行,当我从中创建一个对象时,如

new Future(() => 21)

它只是事件循环中的一个条目。

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

4 个答案:

答案 0 :(得分:5)

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

要测试它,你可以这样写:

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之前

<强> EDIT2:

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

  循环1之前的

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

而不是日程安排顺序。

答案 1 :(得分:4)

当你这样做时:

new Future(() => 21)
.then((v) => v*2)
.then(print);
  • 首先调用new Future(...)构造函数。 这将创建一个Future对象并安排 Timer 来执行您作为参数提供的函数。
  • 然后你致电then。这创造了一个新的未来(称之为未来#2),并在第一个未来增加了一个倾听者。没有安排任何活动。
  • 然后再次致电then。这创造了另一个未来(未来#3)并为未来#2增添了一个倾听者。没有安排任何活动。
  • 然后计时器触发,执行()=>21,第一个未来完成,值为21。
  • 然后立即执行第一个未来的监听器。这会将(v)=>c*2调用21,然后使用值42完成将来的#2。
  • 然后立即执行未来#2的听众。用{42}调用print,打印42并返回null。这样就完成了未来#3,其值为null

目前未来的完成是通过&#34;传播&#34;尝试尽可能多地完成未来的函数,只要它们的侦听器是同步的。这就是为什么完成一个未来将立即完成另一个,没有任何中间微任务。

答案 2 :(得分:1)

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

似乎then (v) => v*2执行的代码再次在Future内执行,因为then始终返回Future

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

  

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

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

答案 3 :(得分:1)

添加到之前的答案中只需要一点点。事件循环&#39;文章很好地解释了这种行为:

  

传递给Future的then()方法的函数执行   在未来完成时立即。 (该功能未入队,   它只是被称为。)

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

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