Menu
CoddyTech

Future 与 async/await

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 76 课,共 110 课。

在实际应用中,许多操作都需要时间,比如从服务器获取数据、读取文件或等待用户输入。Dart 使用 Future 处理这些操作,它表示一个未来某个时刻才能获取的值。

Future 就像一个承诺:“准备好后,我会把结果给你。”你可以使用 Future.delayed() 创建一个 Future,模拟一个需要花费时间的操作:

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

要处理 Future 的结果,请使用 async 和 await。将函数标记为 async,然后使用 await 暂停执行,直到 Future 完成:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

如果不使用 await,你得到的会是 Future<String>,而不是真正的字符串。await 关键字会解包 Future,并给你其中的值。请注意,使用 await 的函数必须标记为 async,并且会自动返回一个 Future。

你也可以从 async 函数中直接返回值,Dart 会自动将它们包装在 Future 中:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // 自动包装为 Future<int>
}
challenge icon

挑战

简单

我们来构建一个天气服务,模拟从不同城市获取天气数据!你将练习使用 Future、async 和 await 来处理需要时间才能完成的操作。

你将把代码分成两个文件:

  • weather_service.dart:创建一个 WeatherService 类,用来模拟获取天气信息。这个类应包含:
    • 一个方法 fetchTemperature(String city),返回 Future<int>。使用 Future.delayed(),设置持续时间为 100 毫秒,以模拟网络延迟。该方法应根据城市名称返回温度:返回城市名称的长度乘以 3。
    • 一个方法 fetchCondition(String city),返回 Future<String>。使用 Future.delayed(),设置延迟为 100 毫秒。如果城市名称的字符数是偶数,就返回 'Sunny',否则返回 'Cloudy'。
    • 一个异步方法 getFullReport(String city),返回 Future<String>。该方法应等待 fetchTemperature 和 fetchCondition 都完成,然后返回格式化后的字符串:'[city]: [temperature]C, [condition]'
  • main.dart:导入天气服务,并演示异步操作的工作方式。你的主函数应为异步函数,并且需要:
    • 创建一个 WeatherService 实例
    • 打印 Fetching weather data...
    • 等待并打印 'Paris' 的完整报告
    • 等待并打印 'Tokyo' 的完整报告
    • 等待并打印 'London' 的完整报告
    • 打印 Done!

注意,每次调用 getFullReport 时,都会等待温度和天气状况都获取完成后,才返回合并后的结果!await 关键字会暂停执行,直到每个 Future 完成。

预期输出:

Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!

亲手试试

import 'weather_service.dart';

Future<void> main() async {
  // TODO: 创建一个 WeatherService 实例
  
  // TODO: 打印 'Fetching weather data...'
  
  // TODO: 等待并打印 'Paris' 的完整报告
  
  // TODO: 等待并打印 'Tokyo' 的完整报告
  
  // TODO: 等待并打印 'London' 的完整报告
  
  // TODO: 打印 'Done!'
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器