当前位置: 代码迷 >> 综合 >> Dart 同步异步相关 --- Future 生成器 Steam
  详细解决方案

Dart 同步异步相关 --- Future 生成器 Steam

热度:87   发布时间:2023-12-17 02:15:20.0

异步是所有开发语言中非常重要的一环,在执行耗时操作的时候不会让主线程长时间无响应,所以理解异步是很必要的一个环节

 

 Future

 

Dart 是单线程的,主线程由一个事件循环来执行(类似 Android 的主线程)。对于异步代码,我们通过 Future 来获取结果(用asycn 和 wait)或者使用Future API:

 

// import 语句用于导入一个包import 'dart:io';void foo() {var file = File('path-to-your-file');file.exists().then((exists) => print('file ${exists ? 'exists' : 'not exists'}')).catchError((e) => print(e));}

 

Dart 2 提供了 async 函数,用来简化这种编程范式。下面这段代码的效果跟上面是一样的:

 

void foo() async {var file = File('path-to-your-file');try {var exists = await file.exists();print('file ${exists ? 'exists' : 'not exists'}');} catch (e) {print(e);}}

 

但是要注意,上面两段代码并不是完全一样的:

import 'dart:io';void main() {foo();bar();}void bar() {var file = File('path-to-your-file');file.exists().then((exists) => print('bar: file ${exists ? 'exists' : 'not exists'}')).catchError((e) => print(e));print('bar: after file.exists() returned');}//在异步代码中使用try、catch和finally来处理错误和清理:void foo() async {var file = File('path-to-your-file');try {var exists = await file.exists();print('bar: file ${exists ? 'exists' : 'not exists'}');print('bar: after file.exists() returned');} catch (e) {print(e);}}// 一种可能的结果:// bar: after file.exists() returned// foo: file not exists// foo: after file.exists() returned// bar: file not exists

 

这里的关键在于,bar 函数里面,file.exists()... 执行完后,会马上执行下面的语句;而 foo 则会等待结果,然后才继续执行

 

官方文档有一句话

 

Before you directly use the Future API, consider using await instead. Code that uses await expressions can be easier to understand than code that uses the Future API.

 

能用asyc await来解决的尽量就用asyc await吧

 

 

Flutter 中支持 async/await 。这一点和 ES7 很像,如下代码所示,只是定义的位置不同。同时异步操作也和 ES6 中的Promise 很像,只是 Flutter 中返回的是 Future 对象,通过 then 可以执行下一步。如果返回的还是 Future 便可以 then().then.() 的流式操作了

 

 

 ///模拟等待两秒,返回OKrequest() async {await Future.delayed(Duration(seconds: 1));return "ok!";}///得到"ok!"后,将"ok!"修改为"ok from request"doSomeThing() async {String data = await request();data = "ok from request";return data;}///打印结果renderSome() {doSomeThing().then((value) {print(value);///输出ok from request});}

 

链接多个异步操作

用then()方法返回一个异步操作,提供了一种有用的方式来以特定的顺序运行多个异步函数。如果用then()注册的回调返回一个异步操作。如果回调返回任何其他类型的值,那么将创建一个新的异步任务并用该值继续完成操作。

Future result = costlyQuery(url);result.then((value) => expensiveWork(value)).then((_) => lengthyComputation()).then((_) => print('Done!')).catchError((exception) {/* Handle exception... */});………try {final value = await costlyQuery(url);await expensiveWork(value);await lengthyComputation();print('Done!');} catch (e) {/* Handle exception... */}```等待多重未来有时您的算法需要调用许多异步函数,并等待它们全部完成后再继续。使用Future.wait()静态方法,并等待它们完成:```Future deleteLotsOfFiles() async =>  ...Future copyLotsOfFiles() async =>  ...Future checksumLotsOfOtherFiles() async =>  ...await Future.wait([deleteLotsOfFiles(),copyLotsOfFiles(),checksumLotsOfOtherFiles(),]);print('Done with all the long steps!');

Streams

 

概念:Stream 就是流的意思,表示发出的一系列的异步数据。可以简单地认为 Stream 是一个异步数据源。它是 Dart 中处理异步事件流的统一 API

思想和rxjava类似,将事件理解为流,Stream 和 Future 是 Dart 异步处理的核心 API。Future 表示稍后获得的一个数据,所有异步的操作的返回值都用 Future 来表示。但是 Future 只能表示一次异步获得的数据。而 Stream 表示多次异步获得的数据。比如界面上的按钮可能会被用户点击多次,所以按钮上的点击事件(onClick)就是一个 Stream 。简单地说,Future将返回一个值,而Stream将返回多次值。

 

Dart 中统一使用 Stream 处理异步事件流,所以可以获得 Stream 的地方很多

将集合(Iterable)包装为 Stream 

Stream 有3个工厂构造函数:fromFuture、fromIterable 和 periodic,分别可以通过一个 Future、Iterable或定时触发动作作为 Stream 的事件源构造 Stream。下面的代码就是通过一个 List 构造的 Stream。

 

使用方式

获得 Stream 用Stream构造方式获得

 订阅 Stream 当你有了一个 Stream 时,最常用的功能就是通过 listen() 方法订阅 Stream 上发出的数据(即事件)

 

var data =[1,2,3,4];var stream = new Stream.fromIterable(data);stream.listen((e)=>print(e), onDone: () => print('Done'));输出:flutter: 1flutter: 2flutter: 3flutter: 4flutter: Done

Stream还有很多操作符,具体在看下文档下,和rxjava一个思路

 

Generators 生成器

 

当您需要懒加载一个序列的值时,请考虑使用生成器函数,Dart已经帮我们封装好了,我们直接拿来用就行了。Dart内置支持两种生成器功能:同步和异步

 

同步生成器:返回一个可迭代对象。

异步生成器:返回一个流对象。

两者区别使用的关键字不同

 

要实现同步生成器函数,将函数体标记为sync*,并使用yield语句传递值:

 

Iterable<int> naturalsTo(int n) sync* {int k = 0;while (k < n) yield k++;}

 

要实现异步生成器函数,将函数体标记为async*,并使用yield语句传递值:

 

Stream<int> asynchronousNaturalsTo(int n) async* {int k = 0;while (k < n) yield k++;}

 

如果你的生成器是递归的,你可以通过使用yield*来提高它的性能:

 

Iterable<int> naturalsDownFrom(int n) sync* {if (n > 0) {yield n;yield* naturalsDownFrom(n - 1);}}