在 Flutter 和 Dart 中优雅地使用 async wait
在我们的业务中,存在复杂的异步依赖关系。传统的then
和await async
有不同的缺点,就是面对复杂的场景时无法写好代码。本文将帮助您处理 js 的孪生兄弟 dart 中复杂的异步操作。让我们开始吧!
信心十足
以JS多年的经验,秒秒钟写出和JS一样的不是很容易吗?开整
长得有那么好吗?我们给这两个方法添加一个返回类型,然后再试一次?
为什么?
到底是什么?为什么会发生这种情况?不是! ! !
不得不说dart类型系统作弊
我们先看下面的代码。你能猜出下面的输出是什么吗?
先别急着打开答案。让我们修改代码并将 double 添加到 list2 中。猜猜输出会是什么?
不知道你猜到了没有,现在我们来揭晓答案
这是为什么? ? ?你真的感到很困惑吗? ? ?
现在请工具人@yaoming来表演
看到上面的对话,你是否有一个问号?为什么定义 List
不起作用?官方的回答是:作为一种设计,Dart 就是这样设计的。推导和转换后,如果不直接声明public,返回的结果会立即使用推导的类型作为实际类型,并立即成为运行时类型。之前宣布的类型立即就没用了。 。 。我只想问,这是一个陷阱吗?可编译,代码直接OJBK,运行时报错。没有这样的事情。 。 。 ,建议大家仔细阅读上面的对话,以免编译后直接跑到火葬场。 。 。
接下来我们看一下方法定义。它有共同的类型,所以问题很容易解决。catchError
中的null]会导致类型不匹配问题
如果不考虑确切的类型♸,我们改为♸列表。 ,所有代码运行
但是有一个问题,就是没有提示类型和提示代码。怎么说呢, dart
不支持不同类型的TS
,这就不错了。同时也不能像js那样直接解构value。只能使用.first
.last
获取值。是不是感觉有点麻瓜的感觉?
这个和之前的JS有些区别。 Dart 是强类型语言,不支持像 TS 那样的多种列表类型。这里我们对返回结果有一个清晰的对象关联。我们直接封装对象来包装结果。有什么不对?完全没问题,这里没有 JS 混乱,并且包含了正确的类型。
现在让我们计划一下。此类应包含成功结果、错误和堆栈信息,以及指示是否发生错误的精确值。根据上面的内容,我们可以得到一个这样的类来包装我们,结果看起来还不错不是吗?
class Any<T> {
final T? ok;
final dynamic err;
final dynamic stackTrace;
bool get hasErr => err != null;
Any.ok(this.ok, {this.err, this.stackTrace});
Any.err(this.err, this.stackTrace, {this.ok});
@override
String toString() {
return 'Any{ok: $ok, err: $err, stackTrace: $stackTrace}';
}
}
复制代码
修改完成代码
import 'dart:async';
Future<void> main() async {
var a = await any(err());
print(a);
print(a.runtimeType);
print(a.hasErr);
print(a.ok);
print(a.ok.runtimeType);
print(a.err);
print('==============================');
var b = await any(succ());
print(b);
print(b.runtimeType);
print(b.hasErr);
print(b.ok);
print(b.ok.runtimeType);
print(b.err);
print('==============================');
var c = await any(voidf());
print(c);
print(c.runtimeType);
print(c.hasErr);
// safe type check. void not any called.
// print(c.ok);
// print(c.ok.runtimeType);
print(c.err);
}
Future<String?> err() async {
throw Error();
}
Future<String> succ() async {
return "success";
}
Future<void> voidf() async {
print('void function.');
}
Future<Any<T?>> any<T>(Future<T> future) {
return future.then<Any<T?>>((T t) {
return Any.ok(t);
}).catchError((err, stackTrace) {
return Any.err(err, stackTrace, ok: null);
});
}
class Any<T> {
final T? ok;
final dynamic err;
final dynamic stackTrace;
bool get hasErr => err != null;
Any.ok(this.ok, {this.err, this.stackTrace});
Any.err(this.err, this.stackTrace, {this.ok});
@override
String toString() {
return 'Any{ok: $ok, err: $err, stackTrace: $stackTrace}';
}
}
复制代码
启动吧
完美了吗? ? ?以后如果像以前一样遇到复杂的业务场景,我们可以隔离不同的业务,直接做简单的决策,告别N层嵌套
var d1 = await any(doSomething1());
if (d1.hasErr) {
// do something..
return;
}
print(d1.ok);
// do something..
var d2 = await any(doSomething2());
if (d2.hasErr) {
// do something..
return;
}
print(d2.ok);
// do something..
var d3 = await any(doSomething3());
if (d3.hasErr) {
// do something..
return;
}
// more task...
复制代码
总结一下
- dart也能优雅地工作
async和
await
只能编译完成OJBK - 始终注意dart类型系统。代码可以编译并不意味着它可以运行。嘻嘻。毕竟,
Promise.any
Future.any
这种方式已经存在了。首先,我这里所说的不是两个元素的排列。那么,any
这个词更能说明回到这里是对还是错,你必须做出正确的选择
作者:尽管如此,世界依然美丽
链接:https ://juejin.cn/post/7014759220771815431
来源:稀土掘金
版权归作者所有。商业转载请联系作者获取授权。非商业转载请注明出处。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。