The Dart VM is single-threaded, so all of an app's code runs in one thread, also called the main isolate. This is because main()
is the function where Dart code starts executing an isolate, because Dart's concurrency model is based on isolates as separate processes that exchange messages. We will talk about isolates in depth in the coming recipes, but if your code doesn't start a new isolate, all of it runs in one isolate. But, in this one isolate, you can have lots of asynchronous pieces of code (let's call them tasks) running at the same time; in what order do they execute, and can we influence that order? It turns out that a better understanding of Dart's event loop and task queuing mechanism enables us to do that. This recipe will clarify Dart's scheduling mechanism and give you hints and tips for an ordered execution of tasks.
Have a look at the program tasks_scheduling.dart
(the tasks are numbered consecutively and according to the way they are started):
import'dart:async'; main() { print('1) main task #1'), scheduleMicrotask(() => print('2) microtask #1')); newFuture.delayed(new Duration(seconds:1), () =>print('3) future #1 (delayed)')); new Future(() => print('4) future #2')); print('5) main task #2'), scheduleMicrotask(() => print('6) microtask #2')); new Future(() => print('7) future #3')) .then((_) => print('8) future #4')) .then((_) => print('9) future #5')) .whenComplete(cleanup); scheduleMicrotask(() => print('11) microtask #3')); print('12) main task #3'), } cleanup() { print('10) whenComplete #6'), }
The following screenshot shows the output of the program, the order of which is explained in the next section:
The main isolate proceeds as follows:
main()
is executed, line after line and synchronously.event-loop
mechanism kicks in, and this looks at the two queues in the system in the following order:In principle, when both queues are empty, the app can exit. Tasks (these are pieces of code to run later, asynchronously) can be scheduled using the following classes and methods from dart:async
:
Future.delayed
, you can specify the execution of a function to occur after a certain duration; this also goes to the event queue.scheduleMicrotask()
function, which appends an item to the microtask queue.Chaining Futures in a series of then
statements effectively ensures that they are executed in that order (see step 1 of the previous recipe). Also, a whencomplete
clause will execute immediately after all the previous then
statements.
So this is the order of execution: main(), then à microtask queue, then event queue, and then delayed tasks.