Menu
CoddyTech

Future và async/await

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 76 trên 110.

Trong ứng dụng thực tế, nhiều thao tác cần thời gian, như lấy dữ liệu từ máy chủ, đọc tệp hoặc chờ đầu vào từ người dùng. Dart xử lý những việc này bằng Future, đại diện cho một giá trị sẽ có trong tương lai.

Future giống như một lời hứa: "Mình sẽ trả kết quả cho bạn khi có sẵn." Bạn có thể tạo một đối tượng bằng Future.delayed() để mô phỏng một thao tác mất thời gian:

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

Để xử lý kết quả của Future, hãy dùng async và await. Đánh dấu hàm của bạn bằng async, rồi dùng await để tạm dừng thực thi cho đến khi Future hoàn tất:

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

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

Nếu không có await, bạn sẽ nhận được một Future<String> thay vì chuỗi thực tế. Từ khóa await mở gói Future và trả về giá trị bên trong. Lưu ý rằng mọi hàm dùng await đều phải được đánh dấu bằng async và tự động trả về một Future.

Bạn cũng có thể trả về giá trị trực tiếp từ các hàm bất đồng bộ (async function). Dart tự động bọc chúng trong Future:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // Tự động được bọc trong Future<int>
}
challenge icon

Thử thách

Dễ

Hãy cùng xây dựng một dịch vụ thời tiết mô phỏng việc lấy dữ liệu thời tiết từ nhiều thành phố! Bạn sẽ luyện cách dùng Future, async và await để xử lý các thao tác cần thời gian mới hoàn tất.

Bạn sẽ sắp xếp code vào hai tệp:

  • weather_service.dart: Tạo lớp WeatherService mô phỏng việc lấy thông tin thời tiết. Lớp của bạn cần có:
    • Phương thức fetchTemperature(String city) trả về một Future<int>. Dùng Future.delayed() với khoảng thời gian 100 milliseconds để mô phỏng độ trễ mạng. Phương thức này cần trả về nhiệt độ dựa trên tên thành phố: lấy độ dài tên thành phố nhân với 3.
    • Phương thức fetchCondition(String city) trả về một Future<String>. Dùng Future.delayed() với độ trễ 100 milliseconds. Trả về 'Sunny' nếu tên thành phố có số ký tự chẵn, nếu không thì trả về 'Cloudy'.
    • Phương thức async getFullReport(String city) trả về một Future<String>. Phương thức này cần chờ cả fetchTemperature và fetchCondition, sau đó trả về chuỗi đã định dạng: '[city]: [temperature]C, [condition]'
  • main.dart: Nhập dịch vụ thời tiết và minh họa cách hoạt động của các thao tác async. Hàm main của bạn cần là async và:
    • Tạo một instance WeatherService
    • In ra Fetching weather data...
    • Chờ rồi in báo cáo đầy đủ cho 'Paris'
    • Chờ rồi in báo cáo đầy đủ cho 'Tokyo'
    • Chờ rồi in báo cáo đầy đủ cho 'London'
    • In ra Done!

Hãy chú ý cách mỗi lần gọi getFullReport đều chờ lấy cả nhiệt độ lẫn điều kiện thời tiết trước khi trả về kết quả kết hợp. Từ khóa await tạm dừng quá trình thực thi cho đến khi mỗi Future hoàn tất!

Đầu ra dự kiến:

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

Tự làm thử

import 'weather_service.dart';

Future<void> main() async {
  // TODO: Tạo một instance của WeatherService
  
  // TODO: In ra 'Fetching weather data...'
  
  // TODO: Chờ rồi in ra báo cáo đầy đủ cho 'Paris'
  
  // TODO: Chờ rồi in ra báo cáo đầy đủ cho 'Tokyo'
  
  // TODO: Chờ rồi in ra báo cáo đầy đủ cho 'London'
  
  // TODO: In ra 'Done!'
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online