A few days ago, Xiao CAI learned some methods of Future to implement asynchronous operation, mainly including constructor method and common static method; Today we will continue to learn more about Future and implement asynchronous operations in async-await mode.

The Future nested

There are many scenarios that require multiple asynchronous processes, and each asynchronous process requires the result returned by the last asynchronous then() before it can continue. In this case, Future nesting can be used. However, if there are many hidden nested methods, the future code maintenance may be affected to some extent, that is, Callback hell is often mentioned.

_futureMoreThen() { Future.delayed(Duration(seconds: 3), () { return 'Future.delayed 3s! '; }).then((val) { print('Future -> then(1) -> $val'); return 'then 1'; }).then((val) { print('Future -> then(2) -> $val'); return 'then 2'; }).then((val) { print('Future -> then(3) -> $val'); return 'then 3'; }).whenComplete(() => print('Future whenComplete! ')); }Copy the code

_futureMoreThen02() { Future.delayed(Duration(seconds: 3), () { return 'Future.delayed 3s! '; }).then((val) { print('Future -> then(1) -> $val'); return Future.delayed(Duration(seconds: 2), () { return 'Future.delayed 2s! '; }).then((val) { print('Future -> then(2) -> $val'); return Future.delayed(Duration(seconds: 2), () { return 'Future.delayed 2s! '; }).then((val) { print('Future -> then(3) -> $val'); }); }); }).whenComplete(() => print('Future whenComplete! ')); }Copy the code

async-await

Futures can also perform asynchronous operations with async-await; The usage scenario is usually a Callback hell caused by multi-level nesting of multiple futures in series, and async-await is used to achieve asynasynism.

async

Async decorates asynchronous methods that eventually encapsulate the return value as a Future object;

await

Await will automatically block the method until the task completes and returns the corresponding value;

Case try

The side dish first tried the basic async-await usage;

  1. Future.delayed() returns a Future object and cannot retrieve the returned data synchronously.
print(_function01()); _function01() { var result = Future.delayed(Duration(seconds: 3), () { return 'Future.delayed 3s! '; }).then((val) => print('Function01 -> then() -> $val')) .whenComplete(() => print('Function01 -> whenComplete! ')); return 'Function01 -> $result'; }Copy the code

  1. The side dish only added the keyword async, modify the method as asynchronous method, still can not directly get the returned data
print(_function01()); Future<String> _function02() async { var result = Future.delayed(Duration(seconds: 3), () { return 'Future.delayed 3s! '; }).then((val) => print('Function02 -> then() -> $val')) .whenComplete(() => print('Function02 -> whenComplete! ')); return 'Function02 -> $result'; }Copy the code

  1. The trick is to add async and await keywords, which the compiler will eventually convert into a Promise(Future) call chain that can be returned after the asynchron completes. The Future cannot set the then() callback method;
print(await _function03()); _function03() async { var result = await Future.delayed(Duration(seconds: 3), () { return 'Future.delayed 3s! '; }); return 'Function03 -> $result'; }Copy the code

  1. The await expression can only be used in an async function, and await can only be used inside an async method.
  2. CatchError () is the most common try-catch-finally method that can be used to catch exceptions. Then ()-catchError()-whenComplete();
await _function04();

_function04(index) async {
  switch (index) {
    case 1:
      await Future.error(ArgumentError.notNull('Input')).catchError((val) => print('Function04 -> $val'));
      break;
    case 2:
      try {
        await Future.error(ArgumentError.notNull('Input'));
      } catch (e) {
        print('Function04 -> catch -> $e');
      } finally {
        print('Function04 -> Finally!');
      }
      break;
  }
}
Copy the code

  1. For Callback hell caused by nested futures, async-await processing is simpler;
await _functionThen(); _functionThen() async { await _itemThen01(); } _itemThen01() async { await Future.delayed(Duration(seconds: 3), () { print('Future -> then(1) -> Future.delayed 3s! '); return _itemThen02(); }); } _itemThen02() async { await Future.delayed(Duration(seconds: 2), () { print('Future -> then(2) -> Future.delayed 2s! '); return _itemThen03(); }); } _itemThen03() async { await Future.delayed(Duration(seconds: 2), () { print('Future -> then(3) -> Future.delayed 2s! '); return 'Future.delayed 2s! '; }).whenComplete(() => print('Future whenComplete! ')); }Copy the code

A small extension

The side dish also encountered async* when trying async-await. The side dish used in bloc state management was both Async * and Stream. Let’s briefly understand the relevant differences.

async*

Async * can also be used for asynchron. Using the async* keyword before a method to mark the method as an asynchron generator, it returns a Stream object and uses yield statements to pass values.

Xiao CAI has a basic understanding of the use of Stream. Generally, data is added through skin and monitored through LISTEN.

The yield keyword adds a value to the output stream of the async* declared one-step generator, somewhat like return, but does not terminate the function;

_function06() async* { for (int i = 1; i <= 10; i++) { await Future.delayed(const Duration(seconds: 1)); yield i; }}Copy the code
await for (int num in _function06()) {
  print('current num = $num');
}
Copy the code

_function06().listen((num) => print('current num = $num'));
Copy the code


Dart Async-await case attempt


Xiaocai’s cognition of Dart asynchronism is not complete, and he will continue to try isolate and EventLoop execution sequence. If there are mistakes and omissions please give more guidance!

Source: Little Monk A Ce