IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> ?Dart-异步编程:futuresasyncawait -> 正文阅读

[移动开发]?Dart-异步编程:futuresasyncawait

文章涵盖如下知识点:

  • 如何以及什么时候使用asyncawait关键字。
  • 如何使用asyncawait来影响执行顺序。
  • 如何使用try-catch处理异步调用异常。
一、为什么异步代码很重要

异步操作允许程序在等待另一个操作完成时完成工作。以下是一些常见的异步操作:

  • 通过网络获取数据。
  • 写入数据库。
  • 从文件中读取数据。

要在Dart中执行异步操作,可以使用Future类以及asyncawait关键字。

看一段有问题的代码:

Future<String> fetchUserOrder() =>
    // Imagine that this function is more complex and slow.
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );
String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}
void main() {
  print(createOrderMessage());
}
Your order is: Instance of 'Future<String>'

下面是示例无法打印fetchUserOrder()最终生成的值的原因:

  • fetchUserOrder()是一个异步函数,它在延迟后提供一个描述用户订单的字符串:“Large Latte”。
  • 要获取用户的订单,createOrderMessage()应该调用fetchUserOrder()并等待它完成。由于createOrderMessage()不等待fetchUserOrder()完成,createOrderMessage()无法获取fetchUserOrder()最终提供的字符串值。
  • 相反,createOrderMessage()获取待完成的工作的表示:未完成的future。
  • 由于createOrderMessage()无法获取描述用户订单的值,因此示例无法将“Large Latte”打印到控制台,而是打印“Your order is:Instance of ‘Future<String>’”。

Future.delayed()是一个工厂命名构造函数,函数原型如下:
Future<T>.delayed(Duration duration, [FutureOr<T> computation()?])
创建一个future,在延迟duration后,运行其可选参数函数computation。
1.computation将在给定的duration时间过后执行,future将随着computation结果的产生而完成。
2.如果computation返回future,则此构造函数返回的future将包含该future的值或错误。
3.如果duration时间为0或更小,则在所有微任务运行后,它将在下一个事件循环迭代中完成。
4.如果省略可选参数computaion,它将被视为computation为()=>null,future将最终以null值完成。在这种情况下,T必须可以为null。
5.如果调用computation抛出异常,则创建的future将以一个错误完成。
———————————————————————————————
FutureOr<T> class:
表示Future<T>或T的值的一种类型。
此类声明是内部[future Or value]泛型类型的公共替代,该泛型类型不是类类型。对此类的引用解析为内部类型。
———————————————————————————————
Duration class:
A Duration represents a difference from one point in time to another. The duration may be “negative” if the difference is from a later time to an earlier.
To create a new Duration object, use this class’s single constructor giving the appropriate arguments:
var fastestMarathon = const Duration(hours: 2, minutes: 3, seconds: 2);
The Duration is the sum of all individual parts. This means that individual parts can be larger than the next-bigger unit. For example, inMinutes can be greater than 59.
assert(fastestMarathon.inMinutes == 123);
var aLongWeekend = const Duration(hours: 88);
assert(aLongWeekend.inDays == 3);
构造函数:
const Duration({int days = 0, int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0})

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, () {// 使用Timer类完成延时逻辑
    if (computation == null) {
      result._complete(null as T);
    } else {
      try {
        result._complete(computation());
      } catch (e, s) {
        _completeWithErrorCallback(result, e, s);
      }
    }
  });
  return result;
}

关键术语:

  • 同步操作:同步操作阻止其他操作执行,直到完成。
  • 同步函数:同步函数只执行同步操作。
  • 异步操作:一旦启动,异步操作允许在完成之前执行其他操作。
  • 异步函数:异步函数至少执行一个异步操作,也可以执行同步操作。
二、什么是future

一个future(小写“f”)是Future(大写“F”)类的一个实例。future表示异步操作的结果,可以有两种状态:未完成或已完成。

注:未完成(Uncompleted)是一个Dart术语,指future产生值之前的状态。

未完成(Uncompleted)和已完成(Completed)

未完成:当你调用异步函数时,它返回一个未完成的future。这个future将等待函数的异步操作完成或抛出错误。(上述有问题的示例代码中就是直接返回了一个未完成的future)

已完成:如果异步操作成功,则future将以值完成。否则,它将以错误完成。

以值完成:用值完成Future<T>类型的future将用T类型的值完成。例如,Future<String>类型的future将生成字符串值。如果future不产生可用值,则future的类型为future<void>。

以错误完成:如果函数执行的异步操作因任何原因失败,则future将以错误完成。

在下面的示例中,fetchUserOrder()返回一个future,这个future在打印控制台完成后完成。因为它不返回可用值,所以fetchUserOrder()的类型为Future<void>。

Future<void> fetchUserOrder() {
  // Imagine that this function is fetching user info from another service or database.
  return Future.delayed(const Duration(seconds: 2), () => print('Large Latte'));
}
void main() {
  fetchUserOrder();
  print('Fetching user order...');
}
Fetching user order...
Large Latte// 2秒后打印

一个future是怎样以一个错误完成的,如下代码:

Future<void> fetchUserOrder() {
	return Future.delayed(const Duration(seconds: 2),
						  () => throw Exception('Logout failed: user ID is invalid'));
}
main() {
	fetchUserOrder();
	print('Fetching user order...');
}
Fetching user order...
Uncaught Error: Exception: Logout failed: user ID is invalid// 2秒后打印

快速回顾:

  • Future<T>实例生成T类型的值。
  • 如果future不产生可用值,则future的类型为Future<void>。
  • future可以处于两种状态之一:未完成或已完成。
  • 当你调用一个返回future的函数时,该函数会将要完成的工作排队,并返回一个未完成的future。
  • 当future的操作完成时,future将以一个值或一个错误完成。
    ?

关键术语:

  • Future:Dart的Future类。
  • future:Future类的实例。
三、使用futureasyncawait

在使用asyncawait时,记住两条基本指导:

  1. 使用异步函数,在函数体前加async关键字;
  2. await关键字仅在异步函数中起作用。
    如果你有一个async函数,你可以使用await关键字来等待一个future完成。

异步执行示例:

foo() async {
  print('foo E');
  String value = await bar();
  print('foo X $value');
}
bar() async {
  print("bar E");
  return "hello";
}
main() {
  print('main E');
  foo();
  print("main X");
}


绿框里面的代码会在foo函数被调用的时候同步执行,在遇到await的时候,会马上返回一个future,剩下的红框里面的代码以then的方式链入这个future被异步调度执行。

main E
foo E
bar E
main X
foo X hello

Process finished with exit code 0

可见print(‘foo X $value’)是在main执行完毕以后才打印出来的。的确是异步执行的。
而以上代码中的foo函数可以以Future方式实现如下,两者是等效的:

foo() {
  print('foo E');
  return Future(bar).then((value) => print('foo X $value'));
}

await并不像字面意义上程序运行到这里就停下来啥也不干等待future完成。而是立刻结束当前函数的执行并返回一个Future对象。函数内剩余代码通过调度异步执行。
await只能在async函数中出现。
async函数中可以出现多个await,每遇见一个就返回一个Future对象, 实际结果类似于用then串起来的回调。
async函数也可以没有await, 在函数体同步执行完毕以后返回一个Future对象。

示例1:同步函数

String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );
void main() {
  print('Fetching user order...');
  print(createOrderMessage());
}
Fetching user order...
Your order is: Instance of 'Future<String>'// 不用等待,直接打印Uncompleted future

示例2:异步函数

Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
    // Imagine that this function is more complex and slow.
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );
Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}
Fetching user order...
Your order is: Large Latte// 2秒后打印Completed future

Process finished with exit code 0

如果其他代码不变,将main()方法改为:

void main() {
	print('Fetching user order...');
	print(createOrderMessage());
}

则打印:

Fetching user order...// 不用等待,直接打印
Instance of 'Future<String>'// 注:没有前缀“Your order is: ”

Process finished with exit code 0// 2秒后打印

断点调试,发现调用顺序如下【0】~【8】:

Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();// 【2、6】
  return 'Your order is: $order';// 【7】
}// 【8、over!】
Future<String> fetchUserOrder() =>
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',// 【5】
    );
void main() {
  print('Fetching user order...');// 【0】
  var orderMsg = createOrderMessage();// 【1】
  print(orderMsg);// 【3】
}// 【4】

为什么改main()为同步函数后的执行顺序是这样的??????

以上两个示例的不同点有3处:

  1. createOrderMessage()函数的返回类型从String变为Future<String>。
  2. async关键字出现在createOrderMessage()和main()方法体之前。
  3. await关键字出现在调用异步函数fetchUserOrder()和createOrderMessage()方法之前。

关键术语:
async:你可以在一个函数体前使用async关键字来标记函数为异步函数。
async function:一个异步函数是一个被async关键字标记的函数。
await:你可以使用await关键字来得到一个异步表达式的完成时结果。await关键字仅在async函数中起作用。

asyncawait的执行流程

一个异步函数同步执行,直到第一个await关键字。

Future<void> printOrderMessage() async {
  print('Awaiting user order...');
  var order = await fetchUserOrder();
  print('fetchUserOrder() completed!');
  print('Your order is: $order');
}
Future<String> fetchUserOrder() {
  // Imagine that this function is more complex and slow.
  return Future.delayed(const Duration(seconds: 4), () => 'Large Latte');
}
Future<void> main() async {
  countSeconds(4);
  await printOrderMessage();
}
// You can ignore this function - it's here to visualize delay time in this example.
void countSeconds(int s) {
  for (var i = 1; i <= s; i++) {
    Future.delayed(Duration(seconds: i), () => print(i));
  }
}
Awaiting user order...
1// 1秒后
2// 2秒后
3// 3秒后
4// 4秒后
fetchUserOrder() completed!
Your order is: Large Latte
四、处理异常
Future<void> printOrderMessage() async {
  try {
    print('Awaiting user order...');
    var order = await fetchUserOrder();
    print(order);
  } catch (err) {
    print('Caught error: $err');
  }
}
Future<String> fetchUserOrder() {
  // Imagine that this function is more complex.
  var str = Future.delayed(
      const Duration(seconds: 4), () => throw 'Cannot locate user order');
  return str;
}
Future<void> main() async {
  await printOrderMessage();
}
Awaiting user order...
Caught error: Cannot locate user order// 4秒后
五、练习:将全部柔和在一起
String addHello(user) => 'Hello $user';

Future<String> greetUser() async {
  var username = await fetchUsername();
  return addHello(username);
}

Future<String> sayGoodbye() async {
  try {
    var result = await logoutUser();
    return '$result Thanks, see you next time';
  } catch (e) {
    return 'Failed to logout user: $e';
  }
}
六、更多

Stream tutorial:学习如何使用异步事件序列。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 11:08:59  更:2022-02-04 11:09:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:50:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码