1

I'm new to Dart. As i understood from some articles and docs (for example this article):

  1. async/await uses the same mechanism as Future, and that is FIFO Event Loop.
  2. Event Loop launches after the execution of main().
  3. async functions runs synchronously up to the first await keyword. Then they pause the execution, and execution returns to the previous function in call stack.
  4. the remaining code is wrapped to the Future and queued to the Event Loop (most unsure point for me).

Based on these points i expect, that the following code:

main() {
  Future(() => print("1"));
  Future(() {
    print("2");
    asyncFunc("2");
  });
  Future(() => print("3"));

  print("main");
  asyncFunc("main");
  print("\nEvent loop starts?\n");
}

asyncFunc(String from) async {
  print("start  [from $from]");
  await (() async => print("middle [from $from]"))();
  print("end    [from $from]");
}

Will create something similar to this event queue after main() execution:
future1 -> future2 -> future3 -> end_from_main
And after execution of future2, event end_from_future2 will be queued to the end:
future1 -> future2 -> future3 -> end_from_main -> end_from_future2

So result output i expect should be:

main
start  [from main]
middle [from main]

Event loop starts?

1
2
start  [from 2]
middle [from 2]
3
end    [from main]
end    [from 2]

But in fact it returns:

main
start  [from main]
middle [from main]

Event loop starts?

end    [from main]
1
2
start  [from 2]
middle [from 2]
end    [from 2]
3

So the conclusion i made: Either async/await events has priority over Fututre. Either they use diffrent mechanism, unrelated to EventLoop. Or maybe i misunderstand something hardly..

julemand101
  • 28,470
  • 5
  • 52
  • 48
  • I think you have a good understanding over the nuances, especially if you're new to Dart! I think that the misunderstanding is that you expect `Future`s to be resolved in a specific order. I do not believe that there is any specified order for resolving `Future`s relative to each other. Therefore it seems reasonable to me that `end [from 2]` is printed before `3`. – jamesdlin Sep 01 '20 at 20:19
  • @jamesdlin thanks for answer. Maybe it really doesn't have specific order. But in many articles i read on this topic, it is stated that `Event queue` is exactly a first-in-first-out queue. – Илья Черезов Sep 01 '20 at 20:37
  • [The default `Future()` constructor schedules a computation using `Timer.run`](https://api.dart.dev/stable/dart-async/Future/Future.html), so it schedules a 0-second `Timer` that will add an event to the event queue rather than adding to the event queue directly. If you instead use the `Future.microtask()` constructor, I think you should get the results you expect. – jamesdlin Sep 01 '20 at 20:55
  • Also see https://stackoverflow.com/questions/24030271/dart-event-queue-and-microtask. – jamesdlin Sep 01 '20 at 20:58
  • Many thanks! This removes a lot of my questions. Yes `Future.microtask()` gives results that i expected. – Илья Черезов Sep 01 '20 at 21:05

1 Answers1

2

What i think i understood:

  • Future can represent either events in Event queue, either tasks in Microtask queue.
    (for example: default Future() constructor puts event to Event queue, Future.microtask() puts task to Microtask queue)
  • await creates Future.than callback to recived Future.

My topic example explanation:

  • First three Futrues put events in Event queue.
  • Future<void> created implicitly in await (() async => print("asyncFunc middle"))() creates "empty" task in Microtask queue (i assume that all implicit Futures are scheduled to Microtask queue). Than await puts remaining instructions (print("end [from main]")) as Future.than callback to this "empty" task.
  • When it comes to Event Loop it first executes "empty" task from Microtask queue. Which ended with callback: print("end [from main]").
  • And than Event loop executes Event queue, where second event spawns similar "empty" task in Microtask queue. And that's why end [from 2] happens before third Future
  • Great research! I just didn't get your conclusion about: *await creates Future.than and Future created await (() async => ...)*. Could you clarify these moments please? So far, it seems that Future.then is an asynchronous callback, but await is a synchronous operation and they are looked not interchangeable for me, aren't they? – Samik Feb 04 '22 at 21:32