Dart event queue and microtask

After some investigation it appears that the right answer is "they will be executed in the next event loop"

To test it you can write something like this:

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");
  });
}

it should output:

in event loop
in event loop
in event loop
before loop 1
before loop 2
before loop 3

Although i'm not sure that you can't break this optimization. So only sure fact is that the firstFuture will complete first and the second - second.

EDIT: The strange part(Obsolete):

With code like this:

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");
  });
}

output is:

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
...

But with this:

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");
  });
}

output is:

in event loop
in event loop
in event loop
before loop 1
before loop 2
before loop 3

EDIT2:

I think i got it. In the first(wrong version) scheduleMicrotask actually never got properly scheduled, but since Dart has eager argument execution it executes print() anyway. So what happens is that all Future getting executed in the next event loop and print all text. That's why output is in call order:

before loop 1
in event loop
before loop 2
in event loop
before loop 3
in event loop

and not in the schedule order.


When you do:

new Future(() => 21)
.then((v) => v*2)
.then(print);
  • First you call the new Future(...) constructor. This creates a Future object and schedules a Timer to execute the function you give as argument.
  • Then you call then. This creates a new future (call it future#2) and adds a listener on the first future. No events are scheduled.
  • Then you call then again. This creates yet another future (future#3) and adds a listener on the future#2. No events are scheduled.
  • Then the timer triggers, and the ()=>21 is executed, and the first future is completed with the value 21.
  • The listener on the first future is then executed immediately. That calls (v)=>v*2 with 21, and then completes future#2 with the value 42.
  • The listener on future#2 is then executed immediately. That calls print with 42, which prints 42 and returns null. This completes future#3 with the value null.

Future completion is currently done through a "propagate" function that tries to complete as many futures as possible, as long as their listeners are synchronous. That is why completing one future will immediately complete another, without any intermediate microtasks.