美文网首页
Dart基础(九)-异步支持

Dart基础(九)-异步支持

作者: 苍眸之宝宝 | 来源:发表于2022-01-12 11:22 被阅读0次

1.简介:

  Dart库充满了返回Future或Stream对象的函数;这些函数都是异步的。这些函数在做一些可能耗时的操作(如I/O)时,会立即返回一个Future或Stream对象,进行函数后面代码的执行,而不需要等待该操作完成后再执行函数后面的代码。
  Dart中使用async``await关键字来实现异步编程,但是和Java、OC等异步不同,代码类似于同步代码,实际上是异步执行的。

关键术语:
同步操作:同步操作阻止其他操作执行,直到它完成。
同步函数:同步函数只执行同步操作。
异步操作:异步操作一旦启动,就允许其他操作在它完成之前执行。
异步函数:一个异步函数至少执行一个异步操作,也可以执行同步操作。

异步场景:

  • 获取网络数据(请求数据、图片下载、文件下载等);
  • 读取数据(从文件、数据库、磁盘中);
  • 写入数据(文件、数据库、磁盘等)。

2.处理Future

  Future表示一个不会立即完成的计算过程。与普通函数直接返回结果不同的是异步函数返回一个将会包含结果的Future。该 Future会在结果准备好时通知调用者。
future与Future:
  future(小写“f”)是Future类的一个实例。future表示异步操作的结果,可以有两种状态:未完成uncompleted或已完成completed
未完成uncompleted
  当调用一个异步函数时,它将返回一个未完成的future。该future表示函数正在等待函数的异步操作完成或抛出错误。
成功的完成Completing with a value
  Future <T>类型的future以T类型的值结束。例如,Future <String>类型的future产生一个字符串值。如果future没有产生一个可用的值,那么future的类型是Future <void>
错误的完成Completing with an error
  如果函数执行的异步操作由于任何原因失败,则future函数将以错误的方式完成。

// 引入Future,并返回一个Future<void>的例子
Future<void> fetchUserOrder() {
  // Imagine that this function is fetching user info from another service or database.
  return Future.delayed(const Duration(seconds: 2), () => print('Large Latte'));
}

// 返回一个future错误的例子
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug
  return Future.delayed(const Duration(seconds: 2),
      () => throw Exception('Logout failed: user ID is invalid'));
}

Futuer和future总结:

  • Future<T>实例产生类型T的值;
  • 如果future没有产生一个可用的值,那么future的类型是future <void>
  • future有两种状态:未完成或已完成;
  • 当调用一个返回future的函数时,该函数将会进入一个异步任务队列中queues,并立即返回一个未完成状态的future
  • future的操作完成时,它会返回一个T类型的值或者一个错误。

3.异步async和等待await

  asyncawait关键字提供了一种声明性的方式来定义异步函数并使用它们的结果;使用的基本原则:

  • 要定义一个异步函数,请在函数体前添加async
  • await关键字只在异步函数中有效;
  • 同步函数中调用异步函数,处理异步函数结果需要.then语法。
Future<String> createOrderMessage() async {
  print("message star");
  var order = await fetchUserOrder3();
  print("message return");
  return 'Your order is: $order';
}

Future<String> fetchUserOrder3() async {
  // Imagine that this function is more complex and slow.
  print("order star");
  var result = await Future.delayed(
    const Duration(seconds: 2), () {
    return 'Large Latte';
  });
  print("order return");
  return result;
}

// 同步函数中调用
print('message top');
createOrderMessage().then((value) {
  print(value);
});
print('message bottom');

// 打印顺序
flutter: message top
flutter: message star
flutter: order star
flutter: message bottom
flutter: order return
flutter: message return
flutter: Your order is: Large Latte

  如何解读上述代码的打印顺序呢?

  • 同步函数中代码是从上往下顺序执行的;
  • 异步函数中,可能是全部同步执行,也可能有同步和也有异步执行;
  • 异步函数中,以await关键字为分界线,await以上包含await调用函数的语句是同步的,await的返回结果和后面的代码是异步执行。
    示例如图,红色的代码为同步执行,绿色代码为异步执行的:
    异步函数的执行.png
      开始解读:
  1. 同步函数首先打印:message top;
  2. 同步调用异步函数createOrderMessage,进入该函数;
  3. 在函数createOrderMessage中,首先同步打印:message star;
  4. 同步调用await fetchUserOrder3(); ,进入函数fetchUserOrder3;
  5. 在函数fetchUserOrder3中,首先同步打印:order star;
  6. 同步调用await Future.delayed ,进行函数Future.delayed调用;
  7. 函数Future.delayed延迟执行,为异步调用,直接返回一个Future<String>的实例future,并加入异步队列中等待执行;
  8. 函数fetchUserOrder3检测到异步执行,直接返回一个future,退出同步执行,将异步部分加入异步队列中等待执行;
  9. 函数createOrderMessage与6相同;
  10. 同步函数中异步函数createOrderMessage的同步部分执行完毕,继续执行下面同步代码,打印:message bottom;
  11. 队列要求先进先出,当最先加入异步队列的任务已经完成后,会以加入的次序执行后续加入的异步代码,后面的打印书序为:
    order return
    message return
    Your order is: Large Latte

3.异步错误error处理:

  在异步函数中,如同同步函数一样使用try-catch处理出现的错误或者异常。

Future<void> printOrderMessage() async {
  try {
    print('Awaiting user order...');
    var order = await fetchUserOrder();
    print(order);
  } catch (err) {
    print('Caught error: $err');
  }
}

Future<String> fetchUserOrder() {
  // Imagine that this function is more complex.
  var str = Future.delayed(
      const Duration(seconds: 4),
      () => throw 'Cannot locate user order');
  return str;
}

Future<void> main() async {
  // 会抛出Cannot locate user order异常
  await printOrderMessage();
}

4.处理流Streams

官方文档
  Stream 是一系列异步事件的序列。其类似于一个异步的 Iterable,不同的是当你向 Iterable 获取下一个事件时它会立即给你,但是 Stream 则不会立即给你而是在它准备好时告诉你。
  Stream概要:

  • Stream提供一个异步的数据序列。
  • 数据序列包括用户生成的事件和从文件读取的数据。
  • 你可以使用Stream API中的listen()方法和await for关键字来处理一个Stream
  • 当出现错误时,Stream提供一种处理错误的方式。
  • Stream 有两种类型:Single-SubscriptionBroadcast
4.1接收Stream事件:

  Stream可以通过许多方式创建,而这些所有的创建方式都可以相同的方式在代码中使用:像使用for循环 迭代一个Iterable一样,我们可以使用 异步for循环 (通常我们直接称之为await for)来迭代Stream中的事件。例如:

Future<int> sumStream(Stream<int> stream) async {
  var sum = 0;
  await for (final value in stream) {
    sum += value;
  }
  return sum;
}

  上面代码只是简单地接收整型事件流中的每一个事件并将它们相加,然后返回(被Future包裹)相加后的整型值。当循环体结束时,函数会暂停直到下一个事件到达或Stream完成。内部使用await for循环的函数需要使用async关键字标记。
下面的示例中使用了async*函数生成一个简单的整型Stream来测试上一个代码片段:

Future<int> sumStream(Stream<int> stream) async {
  var sum = 0;
  await for (final value in stream) {
    sum += value;
  }
  return sum;
}

Stream<int> countStream(int to) async* {
  for (int i = 1; i <= to; i++) {
    yield i;
  }
}

// 调用
var stream = countStream(10);
var sum = sumStream(stream);
sum.then((value) {
  print(value);
});
4.2Stream错误处理:

  当Stream再也没有需要处理的事件时会变为完成状态。与此同时,调用者可以像接收到新事件回调那样接收Stream完成的事件回调。当使用await for循环读取事件时,循环会在Stream完成时停止。

  有时在Stream完成前会出现错误;比如从远程服务器获取文件时出现网络请求失败,或者创建事件时出现 bug;在出现错误时,需要将错误告知使用者。

  Stream可以像提供数据事件那样提供错误事件。大多数Stream会在第一次错误出现后停止,但其也可以提供多次错误并可以在在出现错误后继续提供数据事件。在本篇文档中我们只讨论Stream最多出现并提供一次错误事件的情况。

  当使用await for读取Stream时,如果出现错误,则由循环语句抛出,同时循环结束。你可以使用try-catch语句捕获错误。下面的示例会在循环迭代到参数值等于 4 时抛出一个错误:

Stream<int> countStream(int to) async* {
  for (int i = 1; i <= to; i++) {
    if (i == 4) {
      throw Exception('Intentional exception');
    } else {
      yield i;
    }
  }
}

5.隔离区Isolates

  大多数计算机中,甚至在移动平台上,都在使用多核 CPU。为了有效利用多核性能,开发者一般使用共享内存的方式让线程并发地运行。然而,多线程共享数据通常会导致很多潜在的问题,并导致代码运行出错。

  为了解决多线程带来的并发问题,Dart 使用isolate替代线程,所有的 Dart 代码均运行在一个 isolate 中。每一个isolate有它自己的堆内存以确保其状态不被其它 isolate 访问。

  所有的 Dart 代码都是在一个isolate中运行,而非线程。每个 isolate 都有一个单独的执行线程,并且不与其他的isolate共享任何可变对象。

你可以查阅下面的文档获取更多相关信息:

相关文章

  • Dart基础(九)-异步支持

    1.简介:   Dart库充满了返回Future或Stream对象的函数;这些函数都是异步的。这些函数在做一些可能...

  • Dart(2.2) - 异步支持(Asynchrony supp

    异步支持 Dart有一些语言特性来支持异步编程。 最常见的特性是 async 方法和 await表达式。Dart库...

  • Dart - 异步支持

    Dart 代码库中有大量返回 Future 或 Stream 对象的函数,这些函数都是 异步 的,它们会在耗时操作...

  • Dart语言(九)之异步支持

    简介 Dart类库有非常多的返回Future或者Stream对象的函数。这些函数被称为异步函数。它们只会在设置好一...

  • Flutter笔记--Dart任务调度

    dart异步代码是如何执行的 在Dart基础语法一文中我们了解了dart的一些基础语法,包括异步代码的使用。在da...

  • Dart中的异步编程(Future、scheduleMicrot

    Dart是一门单线程的语言,Dart对异步操作对支持,可以使我们在编写Dart程序时可以异步的来执行耗时操作。这里...

  • Flutter开发之Dart语法基础(三)

    概览一、Dart的异步模型二、Dart的异步操作三、Dart的异步补充 一、Dart的异步模型 1.1 Dart是...

  • Day04-Dart-基础语法三:异步

    概述 Dart的异步模型 Dart的异步操作 Dart的异步补充 一、Dart的异步模型 1.1、Dart是单线程...

  • Dart record

    参考 Dart学习笔记(29):异步编程Dart编程字典子不语归来 的 Dart2基础何小有Dart实例教程 数组...

  • 401--Flutter for iOS 3--线程和异步

    线程和异步 1. 我怎么编写异步的代码? Dart 是单线程执行模型,但是它支持 Isolate(一种让 Dart...

网友评论

      本文标题:Dart基础(九)-异步支持

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