Just as Android has handle, message queues seem to be a system requirement. Flutter also has its own message queues encapsulated in Dart thread type Isolate. However, Flutter provides the Futrue API for manipulating messages and implementing false asynchronism based on message queues


The “asynchronous” mechanism of Flutter

The asynchrony is quoted, so you can see that this asynchrony is not true asynchrony, but false asynchrony. The asynchronism of Flutter is not to start a new thread, but to add tasks to the message queue of the thread to which the Flutter belongs. You can also perform the asynchronous operation as described above

There are two classes of Flutter code: synchronous code and asynchronous code

  • Synchronous code: Traditional code written line by line and executed line by line
  • Asynchronous code: Performed by adding tasks to the ISOLate-owned message queue using the Future APIPseudo asynchronous
  • Execution order: Run synchronous code first, then asynchronous code

Why? Obviously, asynchronous code adds tasks to the message queue, so it must wait until the current code is finished and the thread is free to start executing tasks in the message queue

Here's an example:

void test() {
    print("AA");
    Future(() => print("Futrue"));
    print("BB");
}
~~~~~~~~~~~log~~~~~~~~~~~~~
I/flutter (10064): AA
I/flutter (10064): BB
I/flutter (10064): Futrue
Copy the code

Print (“Futrue”) waited until last…

Flutter provides an API for adding data to message queues: the Future

  • Add tasks to the MicroTask queue
scheduleMicrotask((){
  / /... code goes here...
}); 

new Future.microtask((){
    / /... code goes here...
});
Copy the code
  • Add tasks to the Event queue
new Future(() {
  / /... code goes here...
});
Copy the code

Basic use of Future

A Future object is a message queue-based asynchronous class provided by Flutter. A Future object adds itself to a message queue as a task to queue up to execute

The Future object accepts a function, the task to be performed, with () =>… The shorthand is also ok

void task() {
    print("AA");
}

var futrue = Future(task);
Copy the code

Create a Future task:

  • Future()
  • Future.microtask()
  • Future.sync()– Synchronization task
  • Future.value()
  • Future.delayed()– Add tasks xx later
  • Future.error()– Error handling

Let’s take a look at a few representative ones:

  • Future.sync()– Block the task, which blocks the current code. After the sync task is completed, the code can proceed to the next line
void test() {
    print("AA");
    Future.sync(() = >print("Futrue"));
    print("BB");
}
~~~~~~~~~~~~log~~~~~~~~~~~~~~
I/flutter (10573): AA
I/flutter (10573): Futrue
I/flutter (10573): BB
Copy the code
  • Future.delayed()– Delay the task, specify xx time to add the task to the message queue, if the message queue in front of someone’s execution time is too long, then the execution time can not grasp, this point we should know
void test() {
    print("AA");
    Future.delayed(Duration(milliseconds: 500), () = >print("Futrue"));
    print("BB");
}
~~~~~~~~~~~~log~~~~~~~~~~~~~~
I/flutter (10573): AA
I/flutter (10573): BB
I/flutter (10573): Futrue
Copy the code

The chain call to Future

Future also supports chained calls and is flexible in API usage, offering the following options

  • .then– Execute the Future after it has finished executing, acting as a callback instead of recreating a Future
    Future.delayed(Duration(seconds: 1), () {print(("AAA"));
      return "AA";
    }).then((value){
      print(value);
    });
Copy the code
  • .catchError– Future executes catchError immediately regardless of where an error occurs
    Future.delayed(Duration(seconds: 1), () {throw Exception("AAA");
    }).then((value){
      print(value);
    }).catchError((error){
      print(error);
    });
Copy the code
  • .whenComplete– This method is executed after execution, regardless of whether an exception occurs
    Future.delayed(Duration(seconds: 1), () {
      throw Exception("AAA");
    }).then((value) {
      print(value);
    }).catchError((error) {
      print(error);
    }).whenComplete(() {
      print("complete...");
    });
Copy the code
  • .wait– You can wait for all futuresto be executed before leaving the then method
    Future.wait([
      // Return the result after 2 seconds
      Future.delayed(new Duration(seconds: 2), () {
        return "hello";
      }),
      // Return the result after 4 seconds
      Future.delayed(new Duration(seconds: 4), () {
        return " world";
      })
    ]).then((results) {
      print(results[0] + results[1]);
    }).catchError((e) {
      print(e);
    });
Copy the code

Think about it

Futrue()
    .then()
    .then()
    ...
Copy the code

This is the standard way to go to callback hell


Async/await keywords

The keyword async/await is another API provided by the system to realize asynchronous tasks. At the bottom, async/await is still realized with Futrue, which is a simplification of Futrue in terms of usage. In essence, async/await is realized based on message queue, which is false async. It’s not the same as Isoalte

The nature of async/await is that it comes in pairs

  • async– Decorated methods, methods declared with async are time-consuming
  • await– used when calling async methods, and can also be used inside async methods, ‘await’ means blocking, and the following tasks must wait for the method called ‘await’ to finish executing

Like this:

  anysncTest() async {
    print("Async dormancy start...");
    sleep(Duration(seconds: 1));
    print("Async dormancy end...");
  }

await anysncTest();
Copy the code

In essence, the method called await is wrapping the method in Futrue to be executed in the message queue, just the: future.sync () blocking Future task

Async can also be used directly in layouts

class TestWidgetState extends State<TestWidget> {
  int _count = 0;
 
  @override
  Widget build(BuildContext context) {
    return Material(
        FlatButton(
            onPressed: () async {
                _count = countEven(1000000000);
                setState(() {});
            },
            child: Text(
                _count.toString(),
            )),
    );
  }
Copy the code

Async /await are blocking functions

Experiment 1:
  // This is the asynchronous task code
  aaa() async{
    print("main1...");
    await anysncTest();
    print("main2...");
    print("main3...");
  }

  anysncTest() async {
    print("Async dormancy start...");
    sleep(Duration(seconds: 1));
    print("Async dormancy end...");
  }
  
  // Click the button to execute
    Widget build(BuildContext context) {
    return RaisedButton(
      child: (Text("click!")),
      onPressed: () async  {
        awaitaaa(); }); }Copy the code

async/await

Experiment 2:

So extend the scope and see if async/await is blocking outside async? Someone said that the async/await as coroutines coroutines the key point lies in the competition of resources, in the concept of coroutines, when many collaborators after a collaborators hang cheng cheng, will not block the CPU, CPU back to perform other coroutines method, until there is free again to hang back before implementation of coroutines, although I put up a thread for coroutines, But in fact, THE CPU will not be blocked by coroutine suspension, which is the core advantage of coroutines, greatly improving the efficiency of execution under multi-threading.

From this point we can know if async/await is another coroutine, let’s see if it blocks the CPU, let’s see if the code behind async will execute after await

  // Same set of methods
  aaa() async{
    print("main1...");
    await anysncTest();
    print("main2...");
    print("main3...");
  }

  anysncTest() async {
    print("Async dormancy start...");
    sleep(Duration(seconds: 1));
    print("Async dormancy end...");
  }
  
  // execute. Note that the button click method is not async
  Widget build(BuildContext context) {
    return RaisedButton(
      child: (Text("click!")),
      onPressed: () {
        print("click1...");
        aaa();
        print("click2...");
        print("click3..."); }); }Copy the code
I/flutter ( 5733): click1... I/flutter ( 5733): main1... I/flutter (5733): async sleep start... I/flutter (5733): async dormancy end... I/flutter ( 5733): click2... I/flutter ( 5733): click3... I/flutter ( 5733): main2... I/flutter ( 5733): main3...Copy the code

Await blocking is actually blocking the CPU, so async/await is not a coroutine, but notice that click2 is executed after await blocking, which is an external method of async, It is correct to say that methods with await tag return Futrue objects and that queues are executed only when the thread is idle, which is obviously not the case and the click method has not finished executing

Experiment 3:

This time I’m going to do a comparison experiment and change the click event to async to see the order of execution

  // Same set of methods
  aaa() async{
    print("main1...");
    await anysncTest();
    print("main2...");
    print("main3...");
  }

  anysncTest() async {
    print("Async dormancy start...");
    sleep(Duration(seconds: 1));
    print("Async dormancy end...");
  }
  
  / / execution
    Widget build(BuildContext context) {
    return RaisedButton(
      child: (Text("click!")),
      onPressed: () async {
        print("click1...");
        await aaa();
        print("click2...");
        print("click3..."); }); }Copy the code
I/flutter ( 5733): click1... I/flutter ( 5733): main1... I/flutter (5733): async sleep start... I/flutter (5733): async dormancy end... I/flutter ( 5733): main2... I/flutter ( 5733): main3... I/flutter ( 5733): click2... I/flutter ( 5733): click3...Copy the code

This way, within async methods, execution is strictly sequential


The format of async methods

1. Async methods return values of type Futrue

Methods called with await shall return Futrue objects, so that when async is declared, the return value shall be of type Futrue. Futrue contains the actual return value type

Futrue<String> getData() async {
  data = await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});    
}
Copy the code

Futrue

we don’t need to write it, and Dart will automatically infer that, but we need to know that it is of type Futrue or we will sometimes get a type error

We use ‘await’ with ‘await’, so we can use ‘await’ with ‘return’ directly

String data = await getData();
Copy the code

Remember:

Future is an event. Many of the components of Flutter, such as the GET function of Http and the onRefresh function of RefreshIndicator, are events. Each handle marked with await is also an event, and each Future created will be thrown into the Event queue for security


Stream

A Stream and a Future are pseudo-asynchronous operations. The difference is that a Stream can accept multiple times of data. I won’t elaborate on this, but I’ll discuss it in more detail later

Stream.fromFutures([
  // Return the result after 1 second
  Future.delayed(new Duration(seconds: 1), () {
    return "hello 1";
  }),
  // Throw an exception
  Future.delayed(new Duration(seconds: 2), () {throw AssertionError("Error");
  }),
  // The result is returned after 3 seconds
  Future.delayed(new Duration(seconds: 3), () {
    return "hello 3";
  })
]).listen((data){
   print(data);
}, onError: (e){
   print(e.message);
},onDone: (){

});
Copy the code