美文网首页Flutter圈子
跟我学flutter:我们来举个例子通俗易懂讲解异步(二)ios

跟我学flutter:我们来举个例子通俗易懂讲解异步(二)ios

作者: 王二蛋和他的狗 | 来源:发表于2022-03-31 15:04 被阅读0次

前言

我们在开发flutter应用的时候编写代码,要么是同步代码,要么是异步代码。那么什么是同步什么是异步呢?

  • 同步代码就是正常编写的代码块
  • 异步代码就是Future,async等关键字修饰的代码块

一、时机不同

他们区别于运行时机不同,同步代码先执行,异步代码后执行,即使你的同步代码写在最后,那也是你的同步代码执行,之后运行你的异步代码。

二、机制不同

异步代码运行在 event loop中,类似于Android里的Looper机制,是一个死循环,event loop不断的从事件队列里取事件然后运行。

event loop循环机制

如图所示,事件存放于队列中,loop循环执行


image.png

Dart的事件循环如下图所示。循环中有两个队列。一个是微任务队列(MicroTask queue),一个是事件队列(Event queue)。


image.png

事件队列包含外部事件,例如I/O, Timer,绘制事件等等。
微任务队列则包含有Dart内部的微任务,主要是通过scheduleMicrotask来调度。

  1. 首先处理所有微任务队列里的微任务。
  2. 处理完所有微任务以后。从事件队列里取1个事件进行处理。
  3. 回到微任务队列继续循环。

Dart要先把所有的微任务处理完,再处理一个事件,处理完之后再看看微任务队列。如此循环。

例子:

8个微任务
2个事件

Dart-->执行完8个微任务
Dart-->执行完1个事件
Dart-->查看微任务队列
Dart-->再执行完1个事件
done

异步执行

那么在Dart中如何让你的代码异步执行呢?很简单,把要异步执行的代码放在微任务队列或者事件队列里就行了。

可以调用scheduleMicrotask来让代码以微任务的方式异步执行

    scheduleMicrotask((){
        print('a microtask');
    });

可以调用Timer.run来让代码以Event的方式异步执行

   Timer.run((){
       print('a event');
   });

Future异步执行

创建一个立刻在事件队列里运行的Future:

Future(() => print('立刻在Event queue中运行的Future'));

创建一个延时1秒在事件队列里运行的Future:

Future.delayed(const Duration(seconds:1), () => print('1秒后在Event queue中运行的Future'));

创建一个在微任务队列里运行的Future:

Future.microtask(() => print('在Microtask queue里运行的Future'));

创建一个同步运行的Future:

Future.sync(() => print('同步运行的Future'));

这里要注意一下,这个同步运行指的是构造Future的时候传入的函数是同步运行的,这个Future通过then串进来的回调函数是调度到微任务队列异步执行的。

有了Future之后, 通过调用then来把回调函数串起来,这样就解决了"回调地狱"的问题。

Future(()=> print('task'))
    .then((_)=> print('callback1'))
    .then((_)=> print('callback2'));

在task打印完毕以后,通过then串起来的回调函数会按照链接的顺序依次执行。
如果task执行出错怎么办?你可以通过catchError来链上一个错误处理函数:

 Future(()=> throw 'we have a problem')
      .then((_)=> print('callback1'))
      .then((_)=> print('callback2'))
      .catchError((error)=>print('$error'));

上面这个Future执行时直接抛出一个异常,这个异常会被catchError捕捉到。类似于Java中的try/catch机制的catch代码块。运行后只会执行catchError里的代码。两个then中的代码都不会被执行。

既然有了类似Java的try/catch,那么Java中的finally也应该有吧。有的,那就是whenComplete:


Future(()=> throw 'we have a problem')
    .then((_)=> print('callback1'))
    .then((_)=> print('callback2'))
    .catchError((error)=>print('$error'))
    .whenComplete(()=> print('whenComplete'));

无论这个Future是正常执行完毕还是抛出异常,whenComplete都一定会被执行。

结果执行

把如上的代码在dart中运行看看输出

 print('1');
                var fu1 = Future(() => print('立刻在Event queue中运行的Future'));
                Future future2 = new Future((){
                  print("future2 初始化任务");
                });
                print('2');
                Future.delayed(const Duration(seconds:1), () => print('1秒后在Event queue中运行的Future'));
                print('3');
                var fu2 = Future.microtask(() => print('在Microtask queue里运行的Future'));
                print('4');
                Future.sync(() => print('同步运行的Future')).then((value) => print('then同步运行的Future'));
                print('5');
                fu1.then((value) => print('then 立刻在Event queue中运行的Future'));
                print('6');
                fu2.then((value) => print('then 在Microtask queue里运行的Future'));
                print('7');
                Future(()=> throw 'we have a problem')
                    .then((_)=> print('callback1'))
                    .then((_)=> print('callback2'))
                    .catchError((error)=>print('$error'));
                print('8');
                Future(()=> throw 'we have a problem')
                    .then((_)=> print('callback1'))
                    .then((_)=> print('callback2'))
                    .catchError((error)=>print('$error'))
                    .whenComplete(()=> print('whenComplete'));
                print('9');
                Future future4 = Future.value("立即执行").then((value){
                  print("future4 执行then");
                }).whenComplete((){
                  print("future4 执行whenComplete");
                });
                print('10');


                future2.then((_) {
                  print("future2 执行then");
                  future4.then((_){
                    print("future4 执行then2");
                  });

                });

输出

I/flutter (29040): 1
I/flutter (29040): 2
I/flutter (29040): 3
I/flutter (29040): 4
I/flutter (29040): 同步运行的Future
I/flutter (29040): 5
I/flutter (29040): 6
I/flutter (29040): 7
I/flutter (29040): 8
I/flutter (29040): 9
I/flutter (29040): 10
I/flutter (29040): 在Microtask queue里运行的Future
I/flutter (29040): then 在Microtask queue里运行的Future
I/flutter (29040): then同步运行的Future
I/flutter (29040): future4 执行then
I/flutter (29040): future4 执行whenComplete
I/flutter (29040): 立刻在Event queue中运行的Future
I/flutter (29040): then 立刻在Event queue中运行的Future
I/flutter (29040): future2 初始化任务
I/flutter (29040): future2 执行then
I/flutter (29040): future4 执行then2
I/flutter (29040): we have a problem
I/flutter (29040): we have a problem
I/flutter (29040): whenComplete
I/flutter (29040): 1秒后在Event queue中运行的Future

输出说明:

  • 先输出同步代码,再输出异步代码
  • 通过then串联起的任务会在主要任务执行完立即执行
  • Future.sync是同步执行,then执行在微任务队列中
  • 通过Future.value()函数创建的任务是立即执行的
  • 如果是在whenComplete之后注册的then,那么这个then的任务将放在microtask执行

Completer

Completer允许你做某个异步事情的时候,调用c.complete(value)方法来传入最后要返回的值。最后通过c.future的返回值来得到结果,(注意:宣告完成的complete和completeError方法只能调用一次,不然会报错)。
例子:

test() async {
    Completer c = new Completer();
    for (var i = 0; i < 1000; i++) {
      if (i == 900 && c.isCompleted == false) {
        c.completeError('error in $i');
      }
      if (i == 800 && c.isCompleted == false) {
        c.complete('complete in $i');
      }
    }

    try {
      String res = await c.future;
      print(res); //得到complete传入的返回值 'complete in 800'
    } catch (e) {
      print(e);//捕获completeError返回的错误
    }
  }

相关文章

网友评论

    本文标题:跟我学flutter:我们来举个例子通俗易懂讲解异步(二)ios

    本文链接:https://www.haomeiwen.com/subject/gflnjrtx.html