Cơ bản về Stream
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 77 trên 110.
Trong khi Future trả về một giá trị duy nhất, Stream trả về một chuỗi giá trị theo thời gian. Hãy hình dung nó như một đường ống có thể phát ra nhiều phần dữ liệu, rất phù hợp với các sự kiện, bản cập nhật theo thời gian thực hoặc xử lý dữ liệu từng phần.
Bạn có thể tạo một stream đơn giản bằng Stream.fromIterable() hoặc một hàm tạo bất đồng bộ với async* và yield:
Stream<int> countToThree() async* {
yield 1;
yield 2;
yield 3;
}
Future<void> main() async {
await for (var number in countToThree()) {
print(number);
}
}
// Đầu ra: 1, 2, 3Từ khóa async* đánh dấu một hàm trả về Stream, còn yield phát ra từng giá trị. Để nhận dữ liệu từ stream, hãy dùng await for, câu lệnh này xử lý từng giá trị khi giá trị đó đến.
Bạn cũng có thể nghe một luồng bằng phương thức listen(), phương thức này nhận một hàm callback:
Stream<String> greetings() async* {
yield 'Hello';
yield 'Hi';
yield 'Hey';
}
void main() {
greetings().listen((message) {
print(message);
});
}Điểm khác biệt chính so với Future: Future hoàn tất một lần với một giá trị duy nhất, còn Stream có thể phát ra nhiều giá trị trước khi hoàn tất. Vì vậy, Stream rất phù hợp để xử lý dữ liệu liên tục như tương tác của người dùng, số liệu cảm biến hoặc dữ liệu đến theo từng phần.
Thử thách
DễHãy xây dựng một hệ thống đếm ngược phát ra các giá trị theo thời gian bằng stream! Bạn sẽ tạo một lớp tạo ra dãy số đếm ngược, qua đó tìm hiểu cách stream gửi nhiều giá trị thay vì chỉ một giá trị.
Bạn sẽ sắp xếp code thành hai tệp:
countdown.dart: Tạo lớpCountdownđể tạo các stream đếm ngược. Lớp của bạn cần có:- Một trường
start(int) lưu số bắt đầu đếm ngược - Một hàm khởi tạo nhận số bắt đầu
- Một phương thức
countDown()trả về mộtStream<int>. Dùngasync*vàyieldđể phát ra các số từstartgiảm dần đến0(bao gồm cả0) - Một phương thức
countDownWithMessage()trả về mộtStream<String>. Phương thức này cần phát ra các chuỗi theo định dạng'T-minus [number]'cho mỗi số từstartgiảm dần đến1, sau đó phát ra'Liftoff!'làm giá trị cuối cùng
- Một trường
main.dart: Nhập tệp đếm ngược và minh họa cả hai phương thức stream. Hàm main của bạn cần có từ khóa async và:- Tạo một đối tượng
Countdownbắt đầu từ3 - In ra
Number countdown: - Dùng
await forđể lặp quacountDown()và in ra từng số - In ra một dòng trống
- In ra
Launch sequence: - Dùng
await forđể lặp quacountDownWithMessage()và in ra từng thông báo
- Tạo một đối tượng
Hãy chú ý cách mỗi câu lệnh yield phát ra một giá trị qua stream, còn await for xử lý từng giá trị khi nó đến. Khác với Future chỉ trả về một kết quả, các stream của bạn sẽ phát ra nhiều giá trị theo thứ tự!
Đầu ra dự kiến:
Number countdown:
3
2
1
0
Launch sequence:
T-minus 3
T-minus 2
T-minus 1
Liftoff!Tự làm thử
import 'countdown.dart';
Future<void> main() async {
// TODO: Tạo một instance của Countdown bắt đầu từ 3
// TODO: In ra 'Number countdown:'
// TODO: Dùng await for để lặp qua countDown() và in ra từng số
// TODO: In ra một dòng trống
// TODO: In ra 'Launch sequence:'
// TODO: Dùng await for để lặp qua countDownWithMessage() và in ra từng thông báo
}
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