Asynchronous programming in Dart-Future, async and await

The first Dartis a single-threaded language, so Dartthe 异步操作right support allows us Dartto perform time-consuming operations asynchronously when writing programs. So that you can perform other operations while waiting for one operation to complete. Here are some common asynchronous operations:

  • Get data through the network.

  • Write to the database.

  • Read data from the file.

To Dartperform asynchronous operations in, you can use Futureclasses asyncand awaitkeywords.

 

# Dart's event loop (event loop)

In Dart, there are actually two types of queues:

  1. Event queue ( event queue), including all external I/Oevents: mouse events, drawing events, timers, , isolatetransfer of information between.

  2. Micro task queue ( microtask queue), represents an asynchronous task that will be completed in a short time. It has the highest priority, higher than that event queue, as long as there are tasks in the queue, it can always occupy the event loop. microtask queueThe added tasks are mainly  Dartgenerated internally.

Because  microtask queue the priority is higher  event queue , if  microtask queuethere are too many microtasks, it may occupy the current one event loop. Thus event queue, external events such as touch and drawing in the center cause blocking and stagnation.

In each event loop, Dartalways go to the first one microtask queueto check whether there are executable tasks, if not, then the subsequent event queueprocesses will be processed.

The asynchronous tasks we use the most are the ones with lower priority  event queue.  Provides a layer of encapsulation Dartfor  event queuethe establishment of tasks, which we Dartoften use in Future.

Under normal circumstances, Future the execution of an  asynchronous task is relatively simple:

 

  1. When one Future is declared  , Dart the function execution body of the asynchronous task is put in event queue, and then returns immediately, and the subsequent code continues to execute synchronously.

  2. When synchronous execution code execution is completed, event queueit will be added in accordance with event queuethe order (i.e. declaration order) are sequentially taken out event, and finally the synchronization executing  Future the function body, and subsequent operations.

# Future

Future<T> Class, which represents a  T type of asynchronous operation result. If the asynchronous operation does not require a result, the type is  Future<void>. In other words, the first Futureis a generic class, you can specify the type. If no corresponding type, then Futureit will perform a dynamic derivation type.

# Future basic usage

# Future factory constructor

What is the factory constructor ?

The factory constructor is a kind of constructor. Unlike ordinary constructors, the factory function does not automatically generate an instance, but determines the returned instance object through code.
In Dart, the keyword of the factory constructor is factory. We know that the constructor includes a class name constructor and a named constructor, factorywhich becomes a factory constructor after being added before the constructor. In other words factory, it can be placed before the class name function or before the named function.

Below we pass Futurethe factory constructor to create the simplest one Future.

As you can see, Futurethe factory constructor receives a Dartfunction as a parameter. This function has no parameters and the return value is the FutureOr<T>type.

It can be seen from the printed result that Futurewhen the result is not needed, the returned type is  Future<void>.

Note that the type judgment is performed first, and then Futurethe operation within the printing .

asyncAndawait

The default Futureis to run asynchronously. If you want our Futuresynchronous execution, you can pass asyncand awaitkeywords:

As you can see, ours Futurehas been executed synchronously. awaitWill wait Futurefor the end of execution before continuing to execute the following code.

Keyword asyncsum awaitis part of the Dartlanguage's asynchronous support .

Asynchronous functions are functions that contain keywords in the function header async.

 

async: Used to indicate that the function is asynchronous, and the defined function returns an Futureobject.

await: followed by one Future, which means to wait for the completion of the asynchronous task, and then continue execution after the completion of the asynchronous task. awaitCan only appear inside asynchronous functions . It allows us to perform asynchronous tasks like writing synchronous code without using callbacks.

After printing is finished, it will start to check microtask queuewhether there are tasks in it, and if there are tasks, it will be executed until the microtask queuequeue is empty. Because microtask queuethe priority is the highest. Then go to execute event queue. Generally, the Futurecreated events will be inserted and event queueexecuted in order ( Future.microtaskexcept for the usage method).

Note : In Dart, it async/awaitis just a syntactic sugar, the compiler or interpreter will eventually convert it into a Promise(Future)call chain.
Before Dart 2.0, the async function would return immediately without executing any code in the async function body.
So, if we change the code to the following form:

When we use asynckeywords, it means that the testFuturefunction has become an asynchronous function.

So testFuturethe printing after the function will be executed first .

 

After printing is finished, it will start to check microtask queuewhether there are tasks in it, and if there are tasks, it will be executed until the microtask queuequeue is empty. Because microtask queuethe priority is the highest. Then go to execute event queue. Generally, the Futurecreated events will be inserted and event queueexecuted in order ( Future.microtaskexcept for the usage method).

# Future.value()

Create one that returns the specified valuevalue Future:

void testFuture() async {
    var future = await Future.value(1);
    print("future value: $future.");
}
testFuture();
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
future value: 1.

# Future.delayed()

Create a delayed execution Future:

void testFuture() async {
  Future.delayed(Duration(seconds: 2), () {
    print("Future.delayed 2 seconds.");
  });
}

testFuture();
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
Future.delayed 2 seconds.

FutureSimple to use

# Processing Futureresult

For example Future, if the asynchronous process succeeds, the successful operation is executed, and if the asynchronous process fails, the error is caught or the subsequent operation is stopped. One Futurewill only correspond to one result, either success or failure.

Please remember that Futureall APIthe return value is still an Futureobject, so it can be easily chained .

DartThe following three methods are provided to process Futurethe results.

Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
Future<T> catchError(Function onError, {bool test(Object error)});
Future<T> whenComplete(FutureOr action());

# Future.then()

Used to register a Futurecallback to be called upon completion. If  Future there are more than one then, they will be executed synchronously in the order of the link, and they will also share one event loop.

void testFuture() async {
    Future.value(1).then((value) {
      return Future.value(value + 2);
    }).then((value) {
      return Future.value(value + 3);
    }).then(print);
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
6

At the same time, it then()will be  Futureexecuted immediately after the function body is executed:

void testFuture() async {
     var future = new Future.value('a').then((v1) {
      return new Future.value('$v1 b').then((v2) {
        return new Future.value('$v2 c').then((v3) {
          return new Future.value('$v3 d');
        });
      });
    });
    future.then(print, onError: print);
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
a b c d

Then the problem is coming. If the Futureexecution has been completed, we will get Futurethe reference to this , and then continue to call the then()method. So Darthow will this situation be handled at this time? In this case, Dartthe then()method body that will be added later will be put in microtask queueand executed as soon as possible:

 

  1. Because the testFuture()function is called first , it is printed first future 13.

  2. Then perform the testFuture()following printing.

  3. Start asynchronous task execution.

  4. Perform the highest priority microtask queuetask first scheduleMicrotask, print future 12.

  5. Then Futureexecute again in the order of declaration and print future 1.

  6. Then there  futureFinish, print future 2. The futureFinishexecution is now complete. So it Dartwill be put in futureFinish the thenmethod that will be called  later microtask queue. Because microtask queueof the highest priority. Therefore  futureFinish , it  then will be executed first and printed  future 11.

  7. Then continue to execute event queueinside future 3. Then execute  thenand print  future 4. At the same time then, microtask queuea micro task was added to the method . Because it is being executed at this time event queue, it will not be executed until the next event loop. Therefore, the subsequent then synchronous execution and printing are  continued  future 6. This event loop ends, and the next event loop takes out  future 5 this microtask and prints it  future 5.

  8. microtask queueThe task is completed. Continue to perform event queuethe tasks in. Print  future 7. Then execute  then. What needs to be noted here is: the then return at this time  is a newly created one Future  . So this  thenand the following  then will be added to event queueit.

  9. Continue to perform evnet queuethe tasks inside in order and print  future 10.

  10. In the last event loop, take out the newly added method  evnet queuepassed inside , and the subsequent  , print.future 7thenfuture 8future 9

  11. The whole process is over.

# Future.catchError

Register a callback to capture Futurethe error:

void testFuture() async {
  new Future.error('Future 发生错误啦!').catchError(print, test: (error) {
    return error is String;
  });
}

testFuture();

print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
Future 发生错误啦!

thenCallback onErrorandFuture.catchError

Future.catchErrorThe callback only handles Futurethe error thrown by the original , not the error thrown by the callback function, and onError can only handle the error of the current Future:

void testFuture() async {
    new Future.error('Future 发生错误啦!').then((_) {
       throw 'new error';
    }).catchError((error) {
      print('error: $error');
      throw 'new error2';
    }).then(print, onError:(error) {
      print("handle new error: $error");
    });
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
error: Future 发生错误啦!
handle new error: new error2

# Future.whenComplete

Future.whenComplete It will always be called after the Future is completed, regardless of whether it is completed due to an error or completed normally. For example, the loading dialog box pops up before the network request, and the dialog box is closed after the request ends. And return a Future object:

void testFuture() async {
    var random = new Random();
    new Future.delayed(new Duration(seconds: 1), () {
        if (random.nextBool()) {
          return 'Future 正常';
        } else {
          throw 'Future 发生错误啦!';
        }
    }).then(print).catchError(print).whenComplete(() {
        print('Future whenComplete!');
    });
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
Future 发生错误啦!
Future whenComplete!
在testFuture()执行之后打印。
Future 正常
Future whenComplete!

# Future advanced usage

# Future.timeout

It would have been Futurecompleted after 2s, but it was timeoutdeclared to time out after 1s, so after 1s it Futurewill throw TimeoutException:

void testFuture() async {
    new Future.delayed(new Duration(seconds: 2), () {
      return 1;
    }).timeout(new Duration(seconds:1)).then(print).catchError(print);
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
TimeoutException after 0:00:01.000000: Future not completed

# Future.foreach

Based on a collection object, create a series of Future. And will execute these in order Future. For example, create 3 delays corresponding to the number of seconds based on {1,2,3} Future. The execution result is that 1 is printed after 1 second, 2 is printed after 2 seconds, and 3 is printed after 3 seconds. The total time is 6 seconds:

void testFuture() async {
    Future.forEach({1,2,3}, (num){
      return Future.delayed(Duration(seconds: num),(){print("第$num秒执行");});
    });
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
第1秒执行
第2秒执行
第3秒执行

# Future.wait

Wait for multiple Futurecompletions and collect their results. There are two situations:

 

All Futurehave normal results returned. The Futureresult is the return of all the specified Futureset of results:

void testFuture() async {
    var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);

    var future2 =

    new Future.delayed(new Duration(seconds: 2), ()  => 2);

    var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);

    Future.wait({future1,future2,future3}).then(print).catchError(print);

}

testFuture();

print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
[1, 2, 3]

FutureAn error occurred in one or several of them and occurred error. Then Futurethe return result is the first Futurevalue where the error occurred :

void testFuture() async {
    var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);

    var future2 =

    new Future.delayed(new Duration(seconds: 2), () {

      throw 'Future 发生错误啦!';

    });

    var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);

    Future.wait({future1,future2,future3}).then(print).catchError(print);

}

testFuture();

print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
Future 发生错误啦!

Through this article, we understand the relationship between Dartthe event loop and event queueand microtask queue. At the same time, Dart Futuresome basic usage and advanced usage are introduced, and some usage examples are interspersed to help everyone better understand Dartthe asynchronous operation. Of course, there are some knowledge about Dartasynchronous programming and multi-threading, not too much involved here. I will continue to explain it to you in subsequent articles.

# Future.any

What is returned is Futurethe result of the first execution , regardless of whether the result is correct or error:

  void testFuture() async {
    Future
    .any([1, 2, 5].map((delay) => new Future.delayed(new Duration(seconds: delay), () => delay)))
    .then(print)
    .catchError(print);
  }
  testFuture();
  
  print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
1

# Future.doWhile

Perform an action repeatedly until it returns false or Future and exit the loop. It is suitable for some scenarios that require recursive operations:

void testFuture() async {
    var random = new Random();
    var totalDelay = 0;
    Future.doWhile(() {
        if (totalDelay > 10) {
          print('total delay: $totalDelay seconds');
          return false;
        }
        var delay = random.nextInt(5) + 1;
        totalDelay += delay;
        return new Future.delayed(new Duration(seconds: delay), () {
          print('waited $delay seconds');
          return true;
        });
    }).then(print).catchError(print);
}
testFuture();
  
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
waited 5 seconds
waited 5 seconds
waited 3 seconds
total delay: 11 seconds
null
waited 4 seconds
waited 3 seconds
total delay: 12 seconds
null

# Future.sync

Synchronization will perform its parameters into the function, and then schedule to microtask queuebe done themselves. It is a blocking task, which will block the current code. After syncthe task is executed, the code can go to the next line:

void testFuture() async {
    Future((){
        print("Future event 1");
    });
    Future.sync(() {
        print("Future sync microtask event 2");
    });
    Future((){
        print("Future event 3");
    });
    Future.microtask((){
        print("microtask event");
    });
}
testFuture();
print("在testFuture()执行之后打印。");

Results of the:

Future sync microtask event 2
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 3

But note that if this parameterized function returns one Future:

void testFuture() async {
    Future((){
        print("Future event 1");
    });
    Future.sync(() {
        return Future(() {  print("Future event 2");
      });
    });
    Future((){
        print("Future event 3");
    });
    Future.microtask((){
        print("microtask event");
    });
}
testFuture();
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2
Future event 3

Future.microtask

Create a microtask queuerunning one Future. We know that microtask queuepriority than event queuehigh. The general Futureis in event queueexecution. So the Future.microtaskcreated one Futurewill take precedence over other Futureexecutions:

void testFuture() async {
    Future((){
        print("Future event 1");
    });
    Future((){
        print("Future event 2");
    });
    Future.microtask((){
        print("microtask event");
    });
}
testFuture();
print("在testFuture()执行之后打印。");

Results of the:

在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2

# Written at the end

Through this article, we understand the relationship between Dartthe event loop and event queueand microtask queue. At the same time, Dart Futuresome basic usage and advanced usage are introduced, and some usage examples are interspersed to help everyone better understand Dartthe asynchronous operation. Of course, there are some knowledge about Dartasynchronous programming and multi-threading, not too much involved here. I will continue to explain it to you in subsequent articles.

 

Guess you like

Origin blog.csdn.net/wangletiancsdn/article/details/106637055