Flutter系列之异步篇:Future,Stream,Isolate

目录导航

    • 事件循环与事件队列
    • future vs await
      • future
        • 执行异步代码
        • 处理异步代码的结果
          • then
          • catchError
          • whenComplete
        • 多个异步方法的链式调用
      • await 关键字
    • stream vs await for
    • isolate

Dart是单线程执行模式( single-threaded execution model), Isoalte是对线程的上层封装,代表一个执行环境。不同执行环境(Isolate)之间内存不共享。 Dart的异步操作不一定在另一个线程( Isolate)中执行,而且通常是在同一个线程( Isolate)中执行。

事件循环与事件队列

每个Isoalte都包含一个事件循环器(event loop)和与之关联的两个队列——事件队列(event queue)和微任务队列(microtask queue)。当Main IsolateMain方法执行完毕后,event loop开始依次从与之关联的队列里取出事件执行。这与Android中的Handler机制非常类似,但与之不同的是,Isolate除了event queue外,还有一个microtask queue,microtask queue的优先级高于event queueevent loop总是优先处理microtask queue里的事件。流程图如下:
Flutter系列之异步篇:Future,Stream,Isolate_第1张图片
如上图所示,event loop会首先判断microtask queue是否为空。若不为空,依次取出mcrotask queue中的事件处理,直至它为空;若为空,则尝试从event queue中取出一个事件处理,处理完毕会再次判断microtask queue的情况,不为空的话则优先处理microtask queue,直至它为空。也就是说,每执行完event queue中的一个事件,event loop都要判断下microtask queue的情况以优先处理它。microtask queue的存在,使得事件处理可以存在“插队行为”。

future vs await

future

执行异步代码

我们通过Future对象执行异步代码,Future提供了多种方式传入异步代码,构造器传入是其中一种:

Future asyncMethod() {
  return Future(() {
    //异步代码
  });
}

异步方法会同步返回Future对象作为异步代码的执行结果的代言人,供调用方使用。

  • 没有结果值的异步代码
Future printHelloWorld() {
  return Future(() => print("Hello,world!"));
}
  • 有结果值的异步代码
Future<int> provideOneInt() {
  return Future(() => 1);
}

处理异步代码的结果

then

then方法需传入一个结果处理函数,当异步代码执行完毕后,会执行该函数处理结果。结果处理函数携带一个形参,代表结果值。只有异步代码成功执行(没有抛出异常),then方法传入的结果处理函数才会被调用。

  • 无结果值的异步方法
  printHelloWorld().then((value) => print("print hello world complete!$value"));

由于printHelloWorld没有结果值,所以value的值为null。你可以直接用_代替value

  printHelloWorld().then((_) => print("print hello world complete!"));
  • 有结果值的异步方法
  provideOneInt().then((value) => print("I received a int:$value"));

then方法的返回值为Future类型。当传入的函数返回Future类型时,then直接返回该future;当为其他类型值时,then返回一个包裹该值Future对象。

catchError

catchError用于处理抛出的异常:

  provideOneInt()
      .then((value) => print("I received a int:$value"))
      .catchError((ex) {
    //handle the error
  });

catchError的返回值为Future类型。当捕获到异常时,返回的Future是异常处理函数返回的Future或包裹异常处理函数返回值的Future;当未捕获到异常时,catchError原样传递Future
所以,catchError的调用位置很重要。当在then方法后调用catchError,会捕获异步代码和结果处理代码抛出的异常。如果直接在原始Future上调用catchError,只会捕获异步代码抛出的异常,如:

  provideOneInt().catchError((ex) {
    //handle the error
  }).then((value) => print("I received a int:$value"));

在上面的代码中,catchError只能捕获provideOneInt抛出的异常。而且当抛出异常时,then处理的是错误处理函数的结果,而不是provideOneInt返回的结果。如果没有抛出异常,由于cachError只会原样传递,所以处理的是t
provideOneInt的结果。

whenComplete

then方法传入的结果处理函数只在异步代码成功执行的情况下调用,catchError方法传入的错误处理函数只在代码抛出异常的时候调用。whenComplete传入的处理函数,不管是否抛出异常都会执行。相当于finally

  provideOneInt()
      .then((value) => print("I received a int:$value"))
      .catchError((ex) {
    //handle the error
  }).whenComplete(() {
    //finally code
  });

多个异步方法的链式调用

await 关键字

当调用返回值为Future的异步方法时,如果不想使用Future提供的callback式的api,可以使用await关键字。
await关键字会导致当前方法等待,直至异步方法返回结果,当前方法才继续向下执行。
使用await关键字的前提是当前方法用async修饰。被async关键字修饰,且内部含有await表达式的方法本身是异步的,在方法内部,await 调用的异步方法会同步返回结果。

void printInt() async {
  int value = await provideOneInt();
  print("print the int:$value");
}

异常处理

void printInt() async {
  try {
    int value = await provideOneInt();
    print("print the int:$value");
  } catch (ex) {
    //handle the error
  } finally {
    //finally code
  }
}

stream vs await for

Stream<int> streamIntValues() {
  return Stream<int>.fromIterable([1, 2, 3, 4, 5]);
}
void callbackMode() {
  streamIntValues()
      .listen((value) => print(value), onDone: () => print("on done."));
}

void awaitForMode() async {
  await for (int value in streamIntValues()) {
    print(value);
  }
}

isolate

你可能感兴趣的:(dart,跨平台,flutter)