今天我们来学Dart中的异步编程和Future

异步编程

image-20260418103656415

这里我们简单描述一下进程和线程

进程和线程

进程就是正在运行中的程序,因为电脑上的软件是存在在磁盘上的,即以文件的形式存储的,也就是我们熟悉的文件夹,包括手机平板也是同样的,当我们点开一个软件时,首先这个软件会被加载到内存并获得系统资源,然后开始执行

你使用ctrl + alt +del 打开你的资源管理器就明白了(话说我后台怎么这么多程序,难道是开机自启动? 难怪每次开机这么慢)

image-20260418104835840

程序运行会占用内存,每个进程之间内存隔离互不影响,比如你终止了哔哩哔哩的进程,不会影响其他软件的使用

image-20260418121642703

至于线程,就是程序内部的执行路线,单个进程里有至少一个线程,以浏览器为例

Chrome(进程)

├── 线程1:渲染页面

├── 线程2:网络下载

├── 线程3:执行 JavaScript

└── 线程4:播放音频

即进程给程序分配资源,线程负责执行程序

多线程就是多个线程同时进行执行任务,效率更高,但是单线程就是排队执行任务,上一个任务执行完毕才会轮到下一个

Future

image-20260418163623676

正常情况下是这样的,这里用了回调函数

image-20260418164722903

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main(List<String> args) {
Future f = Future(() {
return "baka";
throw Exception();//throw抛出异常
});

//then 中接收成功状态
f.then((value) {
print(value);
});
//catchError 中接收失败状态
f.catchError((err) {
print("出~错~了 ! zako~ zako~ zako~");
});
}

异常情况下是这样的

image-20260418164823601

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main(List<String> args) {
Future f = Future(() {
//return "baka";
throw Exception();//throw 抛出异常
});

//then 中接收成功状态
f.then((value) {
print(value);
});
//catchError 中接收失败状态
f.catchError((err) {
print("出~错~了 ! zako~ zako~ zako~");
});
}

Flutter的链式调用

上一个 then 返回对象,会在下一个 then 中接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void main(List<String> args) {
Future f = Future(() {
return "baka_00";
//throw Exception;
});

//then 中接收成功状态
f
.then((value) {
return Future(() => "baka_01");
})
.then((value) {
return Future(() => "$value----baka_02");
})
.then((value) {
return Future(() => "$value----baka_03");
})
.then((value) {
print(value);
})
.catchError((err) {
print("出~错~了 ! zako~ zako~ zako~");
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void main() {
Future.value(10)
.then((value) {
print("第1步收到:$value");

// 返回一个新值(会传给下一个 then)
return value + 5;
})
.then((value) {
print("第2步收到:$value");

// 再返回一个值
return value * 2;
})
.then((value) {
print("第3步收到:$value");
})
.catchError((error) {
print("发生错误:$error");
});
}

async和await

image-20260418181659653

你可以发现在函数的参数括号后面有async 指的是 asynchronous(异步),代表当前函数是异步的

关键字 作用
async 声明函数是异步
await 等待异步结果
1
2
3
4
5
6
7
8
Future<String> getName() async {
return "Tom";
}

void main() async {
var name = await getName();
print(name);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2)); //延迟两秒钟,和unity中的协程非常相似
return "数据加载完成";
}

void main() async {
print("开始请求");

var data = await fetchData();

print(data);
print("结束");
}

这里你可以注意到一行代码 Future.delayed(Duration(seconds: 2));

这里其实完整格式是

(new) Future<String>.delayed(Duration duration, [FutureOr<String> Function()? computation])

其中第一个参数Duration duration是指延迟时间例如延迟一秒钟Duration(seconds: 1)

而第二个参数是可选的,即延迟时间之后的返回值,通常为 匿名函数()=>{ return 返回值 },这里的返回值必须和泛型里规定的一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Future<String> getUser() async {
return Future.delayed(Duration(seconds: 1), () {
return "Tom";
});
}

Future<String> getOrder(String user) async {
return Future.delayed(Duration(seconds: 1), () {
return "$user 的订单:iPhone";
});
}

Future<String> getDetail(String order) async {
return Future.delayed(Duration(seconds: 1), () {
return "$order(128GB)";
});
}

void main() async {

print("开始请求");

var user = await getUser();
print("用户:$user");

var order = await getOrder(user);
print("订单:$order");

var detail = await getDetail(order);
print("详情:$detail");

print("结束");

}

try catch

这个和C#里的很像,C#里也有try catch函数,这里 try 指的是 尝试(try block)catch指的是 捕获(catch exception)

1
2
3
4
5
6
7
8
9
void main() {
try {
int a = 10 ~/ 0; // 整数除零,会报错

print(a);
} catch (e) {
print("出错了:$e");
}
}

在异步里就是

1
2
3
4
5
6
7
8
9
10
11
12
13
Future<String> getData() async {
throw Exception("网络挂了");
}

void main() async {
try {
var data = await getData();

print(data);
} catch (e) {
print("捕获到错误:$e");
}
}

其实和if lese的逻辑差不多,只不过这个是应对错误情况使用的

on关键字

这个其实在之前我们学mixin的时候就遇到了,不过on关键字在不同场景下的作用不太一样

在try on中

我们刚才说的try catch的catch的参数是error,也就是接受一切错误并反馈

但是这里try on 就不是了

在这里 on = 只捕获某种指定类型的异常

1
2
3
4
5
6
try {
...
}
on 异常类型 {
...
}

例如刚才的这个例子返回值是 IntegerDivisionByZeroException

image-20260418210253654

而我们只提取这一个问题并输出就行了

1
2
3
4
5
6
7
8
9
void main() {
try {
int a = 10 ~/ 0; // 整数除零,会报错

print(a);
} on IntegerDivisionByZeroException {
print("不能除0");
}
}

image-20260418210401742

甚至还能这样玩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void main() {
try {
//List越界
List list = [1, 2];
print(list[5]);
}on RangeError {
print("越界");
}

try {
// 整数除0
int a = 10 ~/ 0;
} on IntegerDivisionByZeroException {
print("除零");
}

try {
// 格式错误
int.parse("abc");
} on FormatException {
print("格式错误");
}
}

在mixin中

在mixin中我们知道with关键字可以让类使用mixin里的参数和方法

而我们在mixin中使用on就是限制只有哪些类可以使用这个mixin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Animal {
//所有的动物都会吃东西
void eat() {
print("动物吃东西");
}
}

//鸟继承动物类
class Bird extends Animal {
void layEgg() {
print("鸟下蛋");
}
}

//猫继承动物类
class Cat extends Animal {}

//狗继承动物类
class Dog extends Animal {}

//但是飞行和下蛋能力我只允许鸟可以
mixin Fly on Bird {
void fly() {
eat();

layEgg();

print("鸟在飞");
}
}

//这样麻雀类继承鸟类就可以飞了
class Sparrow extends Bird with Fly {}

void main() {
Sparrow s = Sparrow();

s.fly();
}