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>
}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ớpWeatherServicemô 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ộtFuture<int>. DùngFuture.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ộtFuture<String>. DùngFuture.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ộtFuture<String>. Phương thức này cần chờ cảfetchTemperaturevàfetchCondition, sau đó trả về chuỗi đã định dạng:'[city]: [temperature]C, [condition]'
- Phương thức
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!
- Tạo một instance
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!'
}
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
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiThư viện và câu lệnh importGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcBiến thể hiệnKiến thức cơ bản về hàm khởi tạoÔn tập: Máy tính đơn giản4An toàn với giá trị null
Giới thiệu về an toàn với giá trị nullCó thể null và không thể nullToán tử ? và !Từ khóa late và an toàn với giá trị nullToán tử xử lý nullAn toàn với giá trị null trong lớpÔn tập: hệ thống hồ sơ người dùng7Lớp trừu tượng và interface
Lớp trừu tượngPhương thức trừu tượngInterface trong DartInterface ngầm địnhTriển khai và kế thừaNhiều interfaceÔn tập: Máy tính hình10Bộ sưu tập và kiểu tổng quát
Tổng quan về List, Set và MapBộ sưu tập an toàn về kiểuLớp tổng quátPhương thức tổng quátRàng buộc kiểu tổng quátIterable và IteratorÔn tập: Lưu trữ tổng quát2Hàm khởi tạo trong Dart
Hàm khởi tạo mặc địnhHàm khởi tạo có tênDanh sách khởi tạoHàm khởi tạo hằng sốHàm khởi tạo nhà máyHàm khởi tạo chuyển hướngÔn tập: Trình tạo hình dạng5Đóng gói
Thành viên công khai và riêng tưQuy ước tiền tố _Tính riêng tư ở cấp thư việnTìm hiểu sâu về getter và setterChe giấu thông tinÔn tập: hồ sơ học sinh8Mixin
Giới thiệu về MixinTạo MixinSử dụng nhiều MixinTừ khóa on trong MixinMixin và kế thừaMixin và giao diệnÔn tập: hệ thống động vật3Thuộc tính của lớp
Thành viên instance và thành viên tĩnhTrường final và constBiến latePhương thức và trường tĩnhGetter và setterÔn tập: trình quản lý tài khoản ngân hàng6Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChú thích @overrideTừ khóa lớp finalHàm khởi tạo và kế thừaÔn tập: phân cấp nhân viên9Đa hình
Khái niệm cơ bản về đa hìnhĐa hình qua giao diệnKiểm tra kiểu lúc chạyToán tử is và asTừ khóa hiệp biếnÔn tập: Bộ xử lý thanh toán12OOP bất đồng bộ
Future và async/awaitCơ bản về StreamBộ điều khiển StreamHàm khởi tạo bất đồng bộBất đồng bộ trong phương thức lớpÔn tập: Trình lấy dữ liệuTự luyện tập: Trình biên dịch Dart online