Recently, I saw the Future when I was watching Flutter and realized the network request. I thought it was the same as the Promise in JS, but there were some differences in its use. The articles on the Internet were not very detailed, so I collected some information by myself

Threads in Dart

Dart is single-threaded and can be asynchronous. The Event Loop mechanism is called runLoop in iOS. The thread waits to be woken up to do something most of the time, and then processes something when it needs to respond to certain operations, such as user click events and network request return processing

Asynchronous tasks

Dart has two queues, one is EventQueue and the other is MicrotaskQueue. Dart’s Event Loop mechanism continuously polls the Event queue. In each poll, Dart processes MicrotaskQueue first and EventQueue second, creating a priority difference in which microtasks have the highest priority and are created through scheduleMicrotask

scheduleMicrotask(() => print('This is a microtask'));
Copy the code

However, direct use of microtask queues is rare (and nobody stops you if you want to); Asynchronous tasks are more likely to be done in an EventQueue. Dart encapsulates an EventQueue, called a Future, as follows

Future(() => print('Running in Future 1')); // Next event loop outputs the string Future(() =>print(' Runningin Future 2')) .then((_) => print('and then 1')) .then((_) => print('and then2 ')); // Output three consecutive strings after the last event loopCopy the code

A familiar recipe, a familiar feel… Is it a lot like Promise, but it’s a little bit different, and you’re going to wonder, when is this then called? When we declare a Future,Dart queues the function execution body of the asynchronous task, returns it, and synchronously executes subsequent code. Dart places the then on the microtask queue when the Future’s body returns null. Then Dart places the then on the microtask queue as shown in the following example

// Future(() =>print('f1'));
Future(() => print('f2')); //f3 will be synchronized immediately after executionthen 3
Future(() => print('f3')).then((_) => print('then 3'));

//thenFuture(() => NULL).then((_) =>print('then 4'));
Copy the code

Then is executed immediately after the body of the Future function completes execution. Let’s look at a more complicated example


Future(() => print('f1')); // Declare an anonymous Future Future fx = Future(() => null); // Declare a Future fx with the body null // Declare an anonymous Future and register twothen. In the firstthenFuture(() =>print('f2')).then((_) {
  print('f3');
  scheduleMicrotask(() => print('f4'));
}).then((_) => print('f5')); // Declare an anonymous Future and register twothen. The first onethenFuture(() =>print('f6'))
  .then((_) => Future(() => print('f7')))
  .then((_) => print('f8')); // Declare an anonymous Future Future(() =>print('f9')); // register a null fxthen
fx.then((_) => print('f10')); ScheduleMicrotask (() =>print('f11'));
print('f12');
Copy the code

F12, F11, F10, F2, F3, F5, F6, f9, f7, f8.

Since all other statements are asynchronous tasks, print F12 first. Of the remaining asynchronous tasks, the microtask queue has the highest priority, so f11 is printed later; Then print F1 in the order in which the Future declaration was made. Dart puts fx’s THEN into the microtask queue because the microtask queue has the highest priority, so fx’s then is executed first and f10 is printed. Then go to F2 below FX, print F2, and then print F3. F4 is a microtask that is not executed until the next event loop, so subsequent THEN continues to be executed synchronously, printing F5. When this event loop ends, the next event loop takes out the f4 microtask and prints F4. Then go to F6 below F2, print F6, and execute then. The important thing to note here is that this THEN is a Future asynchronous task, so this THEN and subsequent THEN are put into the event queue. F6 and f9. Print F9. For the last event loop, print F7, followed by F8.

An asynchronous function

There are two ways to handle a Future: use. Then, and wait for the Future to be executed before processing it asynchronously; Or use async and await to wait synchronously for the body to complete. Here’s how

// Declare a Future that returns Hello with a 3-second delay, and register onethenHello 2020 Future<String> fetchContent() => Future<String>.delayed(Duration(seconds:3), () =>"Hello")
    .then((x) => "$x 2020");

  main() async{
    print(await fetchContent()); // Wait for Hello 2020 to return}Copy the code

A function that uses the async keyword is also an asynchronous function. This await is similar to async,await in JS; Look at the code below

Future(() => print('f1'))
  .then((_) async {
    print('f5');
    await Future(() => print('f2'));
  })
  .then((_) => print('f3'));
Future(() => print('f4'));
Copy the code

The printed results are F1, F5, F4, F2, F3; Print f1 first, then execute synchronously. But the executor in. Then uses async, which is an asynchronous function. F5 is executed first, then F2 is put into the event queue, so f4 is printed first, then F2, and then F3; This paper reference the geek time Flutter core technology with the practical time.geekbang.org/column/intr… This is the most clear explanation of Future that I have found on the Internet so far, and I also ask the big guy to correct some wrong places