异步编程:futures, async, await

本代码是学习Futureasync await关键字编写异步代码。使用嵌入式DartPad编辑器,您可以通过运行示例代码并完成练习来测试您的知识。
本文主要包含:

  • 如何以及何时使用async await关键字。

异步代码的重要性

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

  • 通过网络获取数据。
  • 写入数据库。
  • 从文件读取数据
    要在Dart中执行异步操作,可以使用Future类和asyncawait关键字。

示例:错误地使用异步函数

以下示例显示了使用异步函数(fetchUserOrder())的错误方法。稍后,您将使用async和修复示例await。在运行此示例之前,请尝试找出问题所在–您认为输出将是什么?

// This example shows how *not* to write asynchronous Dart code.

String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

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”,而是打印“您的订单是:'_ Future的实例'”。

在接下来的部分中,我们将了解Future以及如何使用Future(使用async和await),以便能够将必要的代码编写fetchUserOrder() 为在控制台上打印所需的值('Large Latte')。

关键词:

  • 同步操作:同步操作会阻止其他操作执行到完成。
  • 同步功能:同步功能仅执行同步操作。
  • 异步操作:异步操作一旦启动,就可以在完成之前执行其他操作。
  • 异步函数:异步函数至少执行一个异步操作,也可以执行同步操作。

Fulure是什么?

Fulure表示异步操作的结果,并且可以具有两种状态:未完成或已完成

未完成

当您调用异步函数时,它将返回一个未完成的Fulure。Fulure正在等待函数的异步操作完成或引发错误。

已完成

如果异步操作成功,则Fulure将以一个值完成。否则,它会以错误完成。

Future值

Future是一个Future<T>所以,我们可以将任何值作为返回类型

完成错误

如果该函数执行的异步操作由于任何原因而失败,则将来会出现错误。

示例:介绍Fulure

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

void main() {
  fetchUserOrder();
  print('Fetching user order...');
  //Fetching user order... 
  //Large Latte
}

在以下示例中,fetchUserOrder()返回打印到控制台后完成的Fulure。因为它不返回可用的值,所以 fetchUserOrder()的类型Future<void>。在运行示例之前,请尝试预测将首先打印的内容:“'Large Latte'”或“Fetching user order...”。

示例:错误完成

运行以下示例以查看将来如何完成并出现错误。稍后,您将学习如何处理该错误。

Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug
  return Future.delayed(Duration(seconds: 2),
      () => throw Exception('Logout failed: user ID is invalid'));
}

void main() {
  fetchUserOrder();
  print('Fetching user order...');
  
  //Fetching user order...
  //Uncaught Error: Exception: Logout failed: user ID is invalid
}

在此示例中,fetchUserOrder()显示一个错误,指示用户ID无效。

这个错误的演示是为了理解学习如何使用async和await关键字获得结果

快速总结:

  • Future<T> 实例产生类型的值T

  • 如果Future未产生可用价值,则Future的类型为Future<void>

  • Future可能处于以下两种状态之一:未完成或已完成。

  • 当您调用返回未来的函数时,该函数会将要完成的工作排队,并返回未完成的未来。

  • 当future的操作完成时,future以一个值或一个错误完成。

关键词:

  • Future:Dart Future类。
  • future:Dart Future类的实例。

使用Future:async和await

在async和await关键字提供一个声明的方式来定义异步函数,并使用其结果。使用async和时请记住以下两个基本准则await:

  • **要定义异步函数,要在函数主体之前添加:async **
  • 该await关键字只能在async函数中使用

main()从同步功能转换为异步功能的示例。

void main() async { ··· }

如果函数具有声明的返回类型,则将类型更新为Future<T>,其中T是函数返回的值的类型。如果该函数未明确返回值,则返回类型为 Future<void>

Future<void> main() async { ··· }

现在您有了async函数,可以使用await关键字等待将来完成:

print(await createOrderMessage());

如以下两个示例所示,asyncand await关键字生成的异步代码看起来与同步代码非常相似。异步示例中突出显示了唯一的区别,

  • 同步
String createOrderMessage() {
  var order = fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

void main() {
  print('Fetching user order...');
  print(createOrderMessage());
  // Fetching user order...
  // Your order is: Instance of _Future<String>
}

  • 异步
Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
  // Fetching user order...
  // Your order is: Large Latte
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      Duration(seconds: 2),
      () => 'Large Latte',
    );

Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}

异步示例在三种方面有所不同:

  • 的返回类型createOrderMessage()从变化String到Future<String>
  • 该async关键字的函数体之前出现 createOrderMessage()main()
  • 该await关键字调用异步函数之前出现 fetchUserOrder()createOrderMessage()

关键词:

  • async:您可以async在函数主体之前使用关键字将其标记为异步。
  • 异步函数:async函数是带有async 关键字的函数。
  • await:您可以使用await关键字来获取异步表达式的完整结果。该await关键字只有内工作的async功能。

具有async和await的执行流

一个async函数同步运行直到第一个 await关键字。这意味着在async函数体内,第一个await关键字之前的所有同步代码将立即执行。

示例:异步函数中的执行


Future<void> printOrderMessage() async {
  print('Awaiting user order...');
  var order = await fetchUserOrder();
  print('Your order is: $order');
}

Future<String> fetchUserOrder() {
  // Imagine that this function is more complex and slow.
  return Future.delayed(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));
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342