Dart?异步编程生成器及自定义类型用法详解(异步编程方法)一看就会

随心笔谈1年前发布 编辑
152 0



目录异步支持FutureFuture.thenFuture.catchErrorFuture.whenCompleteFuture.waitasync 和 await处理流(Stream)生成器类型定义元数据

今天介绍一下 Dart 学习的最后一节内容,包括异步的使用、生成器语法以及类型别名的使用。

Dart 类库有非常多的返回或者对象的函数。 这些函数被称为异步函数:它们只会在设置好一些耗时操作之后返回,比如像 IO 操作。而不是等到这个操作完成。

同时,和关键词支持了异步编程,允许您写出和同步代码很像的异步代码。

与 JavaScript 中的非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future 只会对应一个结果,要么成功,要么失败。

注: 的所有API的返回值仍然是一个对象,所以可以很方便的进行链式调用。

为了方便示例,在本例中使用 创建了一个延时任务(实际场景会是一个真正的耗时任务,比如一次网络请求),即2秒后返回结果字符串,然后我们在中接收异步结果并打印结果,代码如下:

Future.delayed(new Duration(seconds: 2),(){
return “hi world!”;
}).then((data){
print(data);
});

如果异步任务发生错误,可以在中捕获错误,将上面示例改为:

Future.delayed(new Duration(seconds: 2),(){
//return “hi world!”;
throw AssertionError(“Error”);
}).then((data){
//执行成功会走到这里
print(“success”);
}).catchError((e){
//执行失败会走到这里
print(e);
});

方法还有一个可选参数,也可以它来捕获异常:

Future.delayed(new Duration(seconds: 2), () {
//return “hi world!”;
throw AssertionError(“Error”);
}).then((data) {
print(“success”);
}, onError: (e) {
print(e);
});

有些时候,我们会遇到无论异步任务执行成功或失败都需要做一些事的场景,比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。这种场景,有两种方法,第一种是分别在或中关闭一下对话框,第二种就是使用的回调,我们将上面示例改一下:

Future.delayed(new Duration(seconds: 2),(){
//return “hi world!”;
throw AssertionError(“Error”);
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});

使用可以做到多个同时出发才会进行后续操作,同 JavaScript 中的方法。

接受一个数组参数,只有数组中所有都执行成功后,才会触发的成功回调,只要有一个执行失败,就会触发错误回调。下面,我们通过模拟 来模拟两个数据获取的异步任务,等两个异步任务都执行成功时,将两个异步任务的结果拼接打印出来,代码如下:

Future.wait([
// 2秒后返回结果
Future.delayed(new Duration(seconds: 2), () {
return “hello”;
}),
// 4秒后返回结果
Future.delayed(new Duration(seconds: 4), () {
return ” world”;
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});

更多 Future 的 api 请自行查询文档。

异步函数是函数体被用修饰符标记的函数。 向函数中添加关键字将使其返回一个 Future。

String lookUpVersion()=> ‘1.0.0’; // 返回String
Future<String> lookUpVersion() async=> ‘1.0.0’; // 返回Future<String>

然后我们可以使用关键字在内部直接接受一个 Future 的的成功回调,就如同 JavaScript 中的那样:

task() async {
try{
String id=await login(“alice”,”******”);
String userInfo=await getUserInfo(id);
await saveUserInfo(userInfo);
// 执行接下来的操作
} catch(e){
// 错误处理
print(e);
}
}

用来表示函数是异步的,定义的函数会返回一个对象,可以使用then方法添加回调函数。 后面是一个,表示等待该异步任务完成,异步完成后才会往下走。注意,必须出现在 函数内部。

注意: 函数的主体不需要使用 Future 的 API。如果需要,Dart 将创建 的对象。如果没有返回一个有用的值,那么将其返回类型。

也是用于接收异步事件数据,和 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。

当需要从 Stream 获取值时,有两个选择:

使用和异步的循环()

注: 在使用之前,请确保它使代码更清晰,并且确实希望等待流(Stream)的所有结果。例如,通常不应该为 UI 事件使用,因为 UI 框架会发送无穷无尽的事件流。

异步循环有以下形式:

await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}

表达式的值必须具有 Stream 类型。执行过程如下:

等待流发出值。

执行循环的主体,并将变量设置为发出的值。

重复1和2,直到流关闭。

要停止侦听流,可以使用或语句,该语句将跳出循环,并从流中取消订阅。

如果在实现异步循环时出现编译时错误,请确保在异步函数中。例如,要在应用程序的函数中使用异步循环,的主体必须标记为:

Future main() async {
// …
await for (var request in requestServer) {
handleRequest(request);
}
// …
}

使用Stream API,如[库的引导]中的描述

Stream.fromFutures([
// 1秒后返回结果
Future.delayed(new Duration(seconds: 1), () {
return “hello 1”;
}),
// 抛出一个异常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError(“Error”);
}),
// 3秒后返回结果
Future.delayed(new Duration(seconds: 3), () {
return “hello 3”;
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
}, onDone: (){

});

当需要延迟地生成一个值序列时,请考虑使用生成器函数。

Dart 内置支持两种生成器函数:

同步生成器:返回 Iterable 对象异步生成器:返回 Stream 对象

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

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

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

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

如果生成器是递归的,可以使用来改进它的性能:

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

在 Dart 中,函数是对象,就像字符串和数字是对象一样。或为函数提供一个类型别名,可以在声明字段和返回类型时使用这个名称。当函数类型被分配给变量时,保留类型信息。

以下代码不使用:

class SortedCollection {
Function compare;
SortedCollection(int f(Object a, Object b)) {
compare=f;
}
}
// Initial, broken implementation.
int sort(Object a, Object b)=> 0;
void main() {
SortedCollection coll=SortedCollection(sort);
// All we know is that compare is a function,
// but what type of function?
assert(coll.compare is Function);
}

上面的代码中,当给分配f时类型信息会丢失。的类型是,当然,的类型是。如果我们更改代码以使用显式名称和保留类型信息,开发人员和工具都可以使用这些信息。

typedef Compare=int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// Initial, broken implementation.
int sort(Object a, Object b)=> 0;
void main() {
SortedCollection coll=SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}

注意: 目前,仅限于函数类型,可能在之后会有所改变。

因为仅仅是别名,所以它们提供了一种检查任何函数类型的方法。例如:

typedef Compare<T>=int Function(T a, T b);
int sort(int a, int b)=> a – b;
void main() {
assert(sort is Compare<int>); // True!
}

使用元数据提供关于代码的附加信息。元数据注释以字符开头,后跟对编译时常量(如)的引用或对常量构造函数的调用。

所有 dart 代码都可以使用两个注释:(弃用注释)和。这里有一个使用注释的例子:

class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated
void activate() {
turnOn();
}
/// Turns the TV’s power on.
void turnOn() {…}
}

可以定义自己的元数据注释(也就是类似 JavaScript 中的装饰器的效果)。这里有一个定义带有两个参数的@todo注释的示例:

library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}

这里有一个使用注释的例子:

import ‘todo.dart’;

@Todo(‘seth’, ‘make this do something’)
void doSomething() {
print(‘do something’);
}

元数据可以出现在库、类、类型定义、类型参数、构造函数、工厂、函数、字段、参数或变量声明之前,也可以出现在导入或导出指令之前。可以使用反射在运行时检索元数据。

核心库的使用

可以参考官方文档中的介绍:A tour of the core libraries

以上就是Dart 异步编程生成器及自定义类型用法详解的详细内容,更多关于Dart 异步编程生成器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:Flutter Dart快速排序算法示例详解Flutter基于Dart Unwrapping Multiple Optional小技巧SafeList?in?Flutter?and?Dart小技巧Dart多态控制反转编码规范实例详解Dart多个future队列完成加入顺序关系及原子性论证Dart语法之变量声明与数据类型实例详解Flutter入门学习Dart语言变量及基本使用概念一文详解Dart如何实现多任务并行

© 版权声明

相关文章