header-bg.jpg
Dart 异步支持之 Future
发表于 2019-09-03 17:09
|
分类于 Dart
|
评论次数 0
|
阅读次数 90

QQ图片20190703111655.png

异步在编程中是一个重要的概念,很多高级语言都是单线程语言,它们在进行一些耗时操作时会造成线程阻塞,例如 Dart 和 JavaScript 都是单线程的,并且都提供了一些相似的特性来支持异步编程,这对于一个学习 Dart 的 JS 开发者无疑是极其舒适的。

Future 对象

Future 和 ECMAScript 6 的 Promise 几乎是一个特性,它们都是异步编程的解决方案,Future 是基于观察者模式的,它有 3 种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。

我们可以使用构造函数来实例化一个 Future 对象,例如:

void main() {
  final request = Future<String>(() => 'request success');
  print(request);// Instance of 'Future<String>'
}

Future 构造函数接受一个函数作为参数,泛型参数决定了返回值的类型,在上面的例子中,Future 返回值被规定为 String

Future 实例生成后,可以用 then 方法指定成功状态的回调函数,例如:

void main() {
  final request = Future<String>(() => 'request success');
  print(request);// Instance of 'Future<String>'
  request.then((e) => print(e));// output: request success
}

then 方法还可以接受一个可选命名参数,参数的名称是 onError,即失败状态的回调函数,例如:

void main() {
  final request = Future<String>(() {
    throw new FormatException('Expected at least 1 section');
  });
  final then = request.then((e) => print('success'), onError: (e) => print(e));
  print(then);

  /**
   * output:
   * Instance of 'Future<void>'
   * FormatException: Expected at least 1 section
   */
}

上面的代码中,Future 实例的函数中抛出了异常,被 onError 回调函数捕获到,并且可以看出 then 方法返回的还是一个 Future 对象,所以其实我们还可以利用 Future 对象的 cathError 进行链式调用从而捕获异常,用法如下:

void main() {
  final request = Future<String>(() {
    throw new FormatException('Expected at least 1 section');
  });
  request.then((e) => print('success'))
      .catchError((e) => print(e));// output: FormatException: Expected at least 1 section
}

Dart 中也内置了很多方法会返回 Future 对象,例如,File 对象的 readAsString 方法,此方法是异步的,它用于读取文件,调用此方法将返回一个 Future 对象。

async 函数与 await 表达式

使用方法

使用 async 关键字可以声明一个异步方法,并且该方法会返回一个 Future,例如:

Future<String> getVersion() async {
  return 'v1.0';
}

checkVersion() async => true;

void main() {
  print(getVersion());// output: Instance of 'Future<String>'
  print(checkVersion());// output: Instance of 'Future<dynamic>'
}

await 表达式必须放入 async 函数体内才能使用,await 表达式会对代码造成阻塞,直至异步操作完成,例如:

void main() async {
  await Future(() => print('request success'));
  print('test');

  /**
   * output:
   * request success
   * test
   */
}

优点

await 表达式能够使异步操作变得更加方便,之前我们使用 Future 对象进行连续的异步操作时,类似如下代码:

void main() {
  Future<String>(() => 'request1')
    .then((res) {
      print(res);
      return Future<String>(() => 'request2');
    })
    .then((res) {
      print(res);
      return Future<String>(() => 'request3');
    })
    .then(print);

  /**
   * output:
   * request1
   * request2
   * request3
   */
}

上面的代码中,每个异步操作都需要等待上个异步操作的完成才可进行,异步回调 then 方法是个链式操作,如果我们使用 await 表达式,可以让这些连续的异步操作将变得更加可读,看来起来就像是同步操作,并且拥有相同的效果,例如:

void main() async {
  final res1 = await Future<String>(() => 'request1');
  print(res1);// output: request1

  final res2 = await Future<String>(() => 'request2');
  print(res2);// output: request2

  final res3 = await Future<String>(() => 'request3');
  print(res3);// output: request3
}

异常处理

因为 await 表达式后面是一个 Future 对象,所以我们可以使用 catchError 来捕获 Future 的异常:

void main() async {
  final res1 = await Future<String>(() => throw 'is error').catchError(print);
  print(res1);

  /**
   * output:
   * is error
   * null
   */
}

或者直接使用 trycatchfinally 来处理异常:

void main() async {
  try {
    final res = await Future<String>(() => throw 'is error');
  } catch(e) {
    print(e);// output: is error
  }
}

发布评论
还没有评论,快来抢沙发吧!