Flutter异步编程指南
作者 | 京东云开发者-京东物流 王志明
原文链接:https://my.oschina.net/u/4090830/blog/8611649
1 Dart 中的事件循环模型
Dart 中有两个队列来执行任务:microtask 队列和 event 队列。
事件循环在 main 方法执行完毕后启动, microtask 队列中的任务会被优先处理。
microtask 队列只处理来自 Dart 内部的任务,event 队列中有来自 Dart 内部的 Future、Timer、isolate message,还有来自系统的用户输入、IO、UI 绘制等外部事件任务。
Dart 中的方法执行不会被打断,因此两个队列中都不适合用来执行计算量大的任务。
一个任务中未被处理的异常只会打断当前任务,后续任务不受影响,程序更不会退出。
1.1 向 microtask 队列中添加任务
scheduleMicrotask(() => print('microtask1'));
Future.microtask(() => print('microtask2'));
1.2 向 event 队列中添加任务
Future(() => print('event task'));
基于以上理论,通过如下代码可以验证 Dart 的事件循环机制:
void main() {
print('main start');
Future(() => print('event task1'));
Future.microtask(() => print('microtask1'));
Future(() => print('event task1'));
Future.microtask(() => print('microtask2'));
print('main stop');
执行结果:
main start
main stop
microtask1
microtask2
event task1
event task1
2 Dart 中的异步实现
Future()
Future.delayed()
Future.microtask()
Future.sync()
2.1 Future()
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
2.2 Future.delayed()
factory Future.delayed(Duration duration, [FutureOr<T> computation()?]) {
if (computation == null && !typeAcceptsNull<T>()) {
throw ArgumentError.value(null, "computation", "The type parameter is not nullable");
}
_Future<T> result = new _Future<T>();
new Timer(duration, () {
if (computation == null) {
result._complete(null as T);
} else {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
}
});
return result;
}
2.3 Future.microtask()
factory Future.microtask(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
scheduleMicrotask(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
2.4 Future.sync()
factory Future.sync(FutureOr<T> computation()) {
try {
var result = computation();
if (result is Future<T>) {
return result;
} else {
// TODO(40014): Remove cast when type promotion works.
return new _Future<T>.value(result as dynamic);
}
} catch (error, stackTrace) {
var future = new _Future<T>();
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
future._asyncCompleteError(replacement.error, replacement.stackTrace);
} else {
future._asyncCompleteError(error, stackTrace);
}
return future;
}
}
void main() {
print('main start');
Future.microtask(() => print('microtask1'));
Future.delayed(new Duration(seconds:1), () => print('delayed event'));
Future(() => print('event1'));
Future(() => print('event2'));
Future.microtask(() => print('microtask2'));
print('main stop');
}
执行结果:
main start
main stop
microtask1
microtask2
event1
event2
delayed event
void main() {
print('main start');
Future.microtask(() => print('microtask1'));
Future.delayed(new Duration(seconds:1), () => print('delayed event'));
Future(() => print('event1'))
.then((_) => print('event1 - callback1'))
.then((_) => print('event1 - callback2'));
Future(() => print('event2')).then((_) {
print('event2 - callback1');
return Future(() => print('event4')).then((_) => print('event4 - callback'));
}).then((_) {
print('event2 - callback2');
Future(() => print('event5')).then((_) => print('event5 - callback'));
}).then((_) {
print('event2 - callback3');
Future.microtask(() => print('microtask3'));
}).then((_) {
print('event2 - callback4');
});
Future(() => print('event3'));
Future.sync(() => print('sync task'));
Future.microtask(() => print('microtask2')).then((_) => print('microtask2 - callbak'));
print('main stop');
}
执行结果:
main start
sync task
main stop
microtask1
microtask2
microtask2 - callbak
event1
event1 - callback1
event1 - callback2
event2
event2 - callback1
event3
event4
event4 - callback
event2 - callback2
event2 - callback3
event2 - callback4
microtask3
event5
event5 - callback
delayed event
then 方法中的回调并不是按照它们注册的顺序来执行。
Future 中的任务执行完毕后会立刻执行 then 方法中的回调,并且回调不会被添加到任何队列中。
如果 Future 中的任务在 then 方法调用之前已经执行完毕了,那么会有一个任务被加入到 microtask 队列中。这个任务执行的就是被传入 then 方法中的回调。
2.5 catchError、whenComplete
Future(() {
throw 'error';
}).then((_) {
print('success');
}).catchError((error) {
print(error);
}).whenComplete(() {
print('completed');
});
error
completed
2.6 async、await
void main() async {
print(await getData());
}
Future<int> getData() async {
final a = await Future.delayed(Duration(seconds: 1), () => 1);
final b = await Future.delayed(Duration(seconds: 1), () => 1);
return a + b;
}
3 Isolate 介绍
3.1 compute
void main() async {
compute<String, String>(
getData,
'Alex',
).then((result) {
print(result);
});
}
String getData(String name) {
// 模拟耗时3秒
sleep(Duration(seconds: 3));
return 'Hello $name';
}
3.2 LoadBalancer
// 用来创建 LoadBalancer
Future<LoadBalancer> loadBalancerCreator = LoadBalancer.create(2, IsolateRunner.spawn);
// 全局可用的 loadBalancer
late LoadBalancer loadBalancer;
void main() async {
// 初始化 LoadBalancer
loadBalancer = await loadBalancerCreator;
// 使用 LoadBalancer 执行任务
final result = await loadBalancer.run<String, String>(getData, 'Alex');
print(result);
}
String getData(String name) {
// 模拟耗时3秒
sleep(Duration(seconds: 3));
return 'Hello $name';
}
4 实用经验
4.1 指定任务的执行顺序
void main() async {
print(await getData());
}
Future<int> getData() {
final completer = Completer<int>();
int value = 0;
Future(() {
return 1;
}).then((result1) {
value += result1;
return Future(() {
return 2;
}).then((result2) {
value += result2;
return Future(() {
return 3;
}).then((result3) {
value += result3;
completer.complete(value);
});
});
});
return completer.future;
}
4.2 使用 then 的链式调用
void main() async {
print(await getData());
}
Future<int> getData() {
int value = 0;
return Future(() => 1).then((result1) {
value += result1;
return Future(() => 2);
}).then((result2) {
value += result2;
return Future(() => 3);
}).then((result3) {
value += result3;
return value;
});
}
4.3 使用 async、await
void main() async {
print(await getData());
}
Future<int> getData() async {
int value = 0;
value += await Future(() => 1);
value += await Future(() => 2);
value += await Future(() => 3);
return value;
}
4.4 取消任务
4.5 CancelableOperation
void main() async {
// 创建一个可以取消的任务
final cancelableOperation = CancelableOperation.fromFuture(
Future(() async {
print('start');
await Future.delayed(Duration(seconds: 3)); // 模拟耗时3秒
print('end');
}),
onCancel: () => print('cancel...'),
);
// 注册任务结束后的回调
cancelableOperation.value.then((val) {
print('finished');
});
// 模拟1秒后取消任务
Future.delayed(Duration(seconds: 1)).then((_) => cancelableOperation.cancel());
}
往期推荐
16款开源的全文搜索引擎
中兴新支点OS桌面环境正式开源,仅104M,速度提升20%
Slint 1.0正式发布,Rust编写的原生GUI工具包
🌟 活动推荐
2023 年 5 月 27-28 日,GOTC 2023 全球开源技术峰会将在上海张江科学会堂隆重举行。
为期 2 天的开源行业盛会,将以行业展览、主题发言、特别论坛、分论坛、快闪演讲的形式来诠释此次大会主题 ——“Open Source, Into the Future”。与会者将一起探讨元宇宙、3D 与游戏、eBPF、Web3.0、区块链等热门技术主题,以及 OSPO、汽车软件、AIGC、开源教育培训、云原生、信创等热门话题,探讨开源未来,助力开源发展。
长按识别下方二维码立即查看 GOTC 2023 详情/报名。
微信扫码关注该文公众号作者