Flutter、Dart中优雅的使用 async await

2021年10月8日17:10:01 发表评论 93 views

我们在实际业务中,存在着复杂的异步依赖关系,传统的 then 和 await async 有着各种各样的缺陷,面对复杂的场景并不能很好的书写代码,这篇文章将带你解决 js 的孪生兄弟 dart 中复杂的异步操作,下面让我们开始吧!

信心满满

根据我们多年的JS经验,秒秒钟写个和JS差不多的不是手到擒来?开整

Flutter、Dart中优雅的使用 async await

看起来是不是非常的nice?我们再给两个方法加上返回类型,再来试试?

Flutter、Dart中优雅的使用 async await

why?

Flutter、Dart中优雅的使用 async await

怎么肥事?为什么会这样,no!!!

不得不说的dart坑爹的类型系统

我们先来看一下下面这段代码,大伙儿猜一下下面会输出啥?

Flutter、Dart中优雅的使用 async await

先不急着揭晓答案,我们再修改一下代码,给list2再添加个double,大伙儿猜猜会输出啥?

Flutter、Dart中优雅的使用 async await

不知道大家有没有猜到哈,现在我们揭晓答案

Flutter、Dart中优雅的使用 async await

Flutter、Dart中优雅的使用 async await

为啥会这样??? 是不是感觉无比懵逼???

Flutter、Dart中优雅的使用 async await

现在有请我们的工具人 @Alex 登场

Flutter、Dart中优雅的使用 async await

看到上面的对话是不是一脸问号?为啥我定义了 List<num> 不起作用?来着官方的答案就是:As design,dart设计如此,在经过推导转换之后,如果不直接声明泛型,返回的结果将直接以推导的类型为实际类型,并且直接变成运行时的类型,在前面声明类型直接无用。。。我就问一句,这个坑不坑,编译可以编译过,代码直接OJBK,跑的时候报错,这TM也没谁了。。。,建议大伙儿仔细研读上面的对话,免得编译一时爽,运行直接火葬场。。。

我们来看看 then 这个方法的定义,确实带有一个泛型,那么问题好办了

Future<R> then<R>(FutureOr<R> onValue(T value), {Function? onError});
复制代码

完善代码

经历过上面的求证,我们修改一下先前的代码

首先,如果我们要返回一个确定类型的列表,那么在 catchError 中返回 [err, null] 将会出现类型不匹配的问题

Flutter、Dart中优雅的使用 async await

如果不考虑确切的类型,我们将列表修改为 List<dynamic> ,代码啥的全都跑起来了

Flutter、Dart中优雅的使用 async await

但是这样存在一个问题,那就是没有类型提示,以及代码提示了,怎么说呢,dart 不支持 TS 的多种类型,挺好的。同时,取值并不能像js那样,直接解构列表,取值只能使用 .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}';
  }
}
复制代码

我们来运行一下

Flutter、Dart中优雅的使用 async await

是不是非常完美???后面再遇到像先前那样复杂的业务场景,抽离一下不同的业务,我们可以直接进行简单的判断,告别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也是可以优雅的使用 asyncawait 的,只要进行简单的包装一下,完全OJBK
  • 时刻注意dart的类型系统,代码能编译,并不能代表能跑,嘻嘻
  • 有人可能好奇我为什喜欢用 any 这个词,而不是 to ,毕竟 Promise.any Future.any 已经有这个方法了。首先,我这儿不是一个两个元素的数组,然后,any 这个词也比较能表示出这里的返回不是正确就是错误,需要作出正确的选择

作者:尽管如此世界依然美丽
链接:https://juejin.cn/post/7014759220771815431
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: