Bắt đầu
Cài đặt RxJS và xây dựng những stream đầu tiên.
Bạn đã hiểu RxJS dùng để mô tả dữ liệu thay đổi theo thời gian, nhưng từ mental model đến một pipeline chạy được vẫn còn vài mảnh ghép: cài package thế nào, subscribe ở đâu, đọc timeline ra sao và nhìn vào đâu khi output không đúng.
Nhóm Bắt đầu nối các mảnh đó bằng một vòng học ngắn: thiết lập môi trường, đọc stream, chạy stream rồi quan sát lifecycle của nó. Đích đến không phải là thuộc nhiều operator; bạn cần tự viết và giải thích được một pipeline nhỏ trước khi sang phần chuyên sâu.
Phạm vi phiên bản
Nội dung trong nhóm này dùng public API ổn định của RxJS 7.8.x và TypeScript. Các ví dụ import trực tiếp từ rxjs, không dựa vào API thử nghiệm của RxJS 8.
Mục lục
- Sau nhóm này bạn làm được gì
- Nhìn trước một pipeline hoàn chỉnh
- Bản đồ năm bài bắt đầu
- Cách học nhóm này
- Checklist hoàn thành
- Những bẫy nên tránh ngay từ đầu
- Đi tiếp sau nhóm Bắt đầu
- Nguồn tham khảo
Sau nhóm này bạn làm được gì
Kết thúc năm bài, bạn nên có thể tự làm những việc sau mà không cần sao chép nguyên một snippet có sẵn:
- cài
rxjsvào project TypeScript và kiểm tra import hoạt động; - nhận ra source, operator, Observable đầu ra và Observer trong một pipeline;
- đọc được
next,error,completecùng chiều thời gian trên marble diagram; - dùng
pipe()để ghép các phép biến đổi mà không sửa source Observable; - subscribe bằng một Observer có chủ đích, rồi xác định khi nào execution kết thúc;
- dùng log hoặc
tapđể quan sát pipeline mà không biến debug thành logic nghiệp vụ.
Đây là chuẩn đầu ra thực dụng hơn việc nhớ tên operator. Khi một stream cho kết quả sai, sáu kỹ năng trên giúp bạn khoanh vùng vấn đề trước khi thêm operator mới.
Nhìn trước một pipeline hoàn chỉnh
Ví dụ dưới đây là hình dạng bạn sẽ gặp xuyên suốt nhóm này. Source phát bốn số, filter giữ số chẵn, map đổi chúng thành nhãn, còn Observer nhận các notification cuối pipeline.
Code TypeScript
import { filter, map, of } from 'rxjs';
const source$ = of(1, 2, 3, 4);
const labels$ = source$.pipe(
filter((value) => value % 2 === 0),
map((value) => `item-${value}`),
);
labels$.subscribe({
next: (value) => console.log('next:', value),
error: (error: unknown) => console.error('error:', error),
complete: () => console.log('complete'),
});Kết quả:
next: item-2
next: item-4
completeof() phát các giá trị này đồng bộ rồi complete. Observable không mặc định là “tác vụ chạy nền”; timing phụ thuộc source và scheduler được dùng.
Đọc pipeline theo luồng dữ liệu
source$ (1) ── (2) ── (3) ── (4) ── complete
│ │
filter số chẵn (2) (4)
│ │
map thành nhãn "item-2" "item-4"
│ │
Observer next(value) next(value) ── completeCó thể đọc ví dụ theo bốn bước:
of(1, 2, 3, 4)tạo source Observable. Chưa có execution nào chạy ở thời điểm khai báo.pipe(...)trả vềlabels$, một Observable mới; nó không sửasource$.subscribe(...)bắt đầu execution, nên source mới phát dữ liệu qua từng operator.- Source complete sau
4; completion đi qua pipeline và gọi callbackcompletecủa Observer.
Hãy tách định nghĩa pipeline khỏi thời điểm chạy pipeline. Đây là khác biệt nhỏ trên code nhưng rất quan trọng khi bạn gặp nhiều subscription, HTTP request hoặc event stream sống lâu.
Cách đọc code RxJS
Đi từ source đến pipe() để theo dõi dữ liệu đi xuôi, rồi tìm subscribe() để biết ai khởi động và sở hữu execution. Cuối cùng, kiểm tra đường kết thúc: complete, error hay unsubscribe.
Bản đồ năm bài bắt đầu
Mỗi bài thêm một kỹ năng vào cùng pipeline, nên thứ tự dưới đây có chủ đích:
| Bài | Câu hỏi bài giải quyết | Kết quả bạn cần đạt |
|---|---|---|
| Cài đặt RxJS | Package, TypeScript và script chạy ví dụ được thiết lập thế nào? | Chạy được một file import public API từ rxjs. |
| Marble diagram | Giá trị, thời gian, complete, error và unsubscribe được biểu diễn ra sao? | Đọc được lifecycle của một stream trước khi nhìn code. |
| Subscribe và Observer | Ai nhận notification và điều gì xảy ra khi subscribe? | Viết Observer rõ ba channel next, error, complete. |
| Pipe và operator | Làm sao ghép nhiều phép biến đổi mà pipeline vẫn đọc được? | Tách source, transformation và side effect đúng vai trò. |
| Playground và debug | Khi output sai hoặc stream không kết thúc, quan sát ở đâu? | Dùng log, tap và teardown signal để lần theo execution. |
Nếu một bài chi tiết vẫn đang được bổ sung, bạn có thể dùng ví dụ trên làm bài thực hành tối thiểu: chạy nó, dự đoán output trước, rồi thay đổi từng phần và giải thích kết quả.
Cách học nhóm này
Nếu đây là pipeline đầu tiên của bạn
Đi theo thứ tự trong bảng. Sau bài cài đặt, giữ một file playground duy nhất và sửa nó qua từng bài; như vậy bạn quan sát được kiến thức mới thay đổi cùng một execution ra sao, thay vì mỗi lần lại bắt đầu bằng một ví dụ không liên quan.
Sau mỗi thay đổi, làm ba việc: viết output dự đoán, chạy code, rồi giải thích điểm khác nhau. Nếu chỉ chạy đến khi “thấy đúng”, bạn dễ bỏ qua lý do stream complete, error hoặc còn mở.
Nếu bạn đã từng dùng RxJS
Hãy bắt đầu ở chỗ thường làm bạn phải đoán. Nếu code chạy nhưng timeline khó hiểu, đọc Marble diagram. Nếu bạn hay viết subscribe(value => ...) rồi quên error và cleanup, chuyển thẳng đến Subscribe và Observer. Nếu pipeline chỉ khó khi debug, dùng bài playground như checklist quan sát.
Dù đã có kinh nghiệm, hãy chạy lại ví dụ tối thiểu một lần trong chính môi trường của project. Nó tách lỗi setup khỏi lỗi tư duy pipeline, nên bạn không phải debug hai vấn đề cùng lúc.
Checklist hoàn thành
Đừng đánh dấu nhóm này là xong chỉ vì code đã in ra hai dòng. Hãy tự kiểm tra:
- Tôi chỉ ra được source, từng operator, output Observable và Observer trong ví dụ.
- Tôi giải thích được vì sao
1và3không tới Observer. - Tôi biết chính xác lời gọi nào bắt đầu execution.
- Tôi phân biệt được
complete,errorvà consumer gọiunsubscribe(). - Tôi có thể vẽ timeline của ví dụ bằng ký hiệu marble đơn giản.
- Tôi biết chèn
tapở đâu để quan sát trước và sau một operator. - Tôi chạy được ví dụ trong playground mà không cần sửa import theo kiểu nội bộ của package.
Nếu còn vướng một mục, quay lại bài tương ứng trong bảng. Không cần học thêm operator cho đến khi vòng đời của pipeline nhỏ này đã rõ.
Những bẫy nên tránh ngay từ đầu
- Cho rằng tạo Observable là chạy ngay. Nhiều Observable là lazy; ví dụ trên chỉ thực thi khi có
subscribe(). - Cho rằng mọi Observable đều bất đồng bộ.
of()có thể phát và complete ngay trong cùng call stack. Đừng suy timing chỉ từ kiểuObservable. - Nhét business logic vào
subscribe. Subscriber nên là boundary nhận kết quả hoặc tạo side effect. Phép biến đổi dữ liệu thường dễ đọc, tái sử dụng và test hơn khi nằm trongpipe(). - Dùng
tapđể thay đổi dữ liệu.tapphù hợp để log hoặc quan sát side effect; dùngmapkhi output cần giá trị mới. - Chỉ viết callback
nextrồi quên đường kết thúc. Một demo ngắn có thể ổn, nhưng code thật cần quyết định rõ error đi đâu và tài nguyên được dọn lúc nào. - Subscribe lồng nhau để nối hai tác vụ. Cách này sớm làm error handling và teardown bị chia đôi. Khi sang higher-order Observable, hãy chọn flattening operator theo concurrency policy thay vì nested subscribe.
Log không chứng minh được cleanup
Không còn output chưa chắc execution đã kết thúc. Với timer, DOM event hoặc WebSocket, hãy kiểm tra complete, error, unsubscribe và teardown thay vì chỉ nhìn các dòng next.
Đi tiếp sau nhóm Bắt đầu
Sau khi hoàn thành checklist, bước hợp lý nhất là đi sâu vào cách Observable tạo execution và cách Subscription dọn tài nguyên. Nếu mental model về lifecycle vẫn chưa chắc, ôn phần nền tảng trước khi học thêm operator.
Cài đặt RxJS
Thiết lập môi trường TypeScript và chạy ví dụ đầu tiên.
Marble diagram
Nhìn value, thời gian và terminal signal trên cùng timeline.
Observable & Subscription
Đi sâu vào execution, producer và teardown tài nguyên.
Vòng đời của stream
Ôn lại contract của next, error, complete và unsubscribe.
Nguồn tham khảo
- RxJS — Introduction — vai trò của Observable, Observer, Subscription và operators trong thư viện.
- RxJS — Observable — tính lazy của execution, notification contract và teardown.
- RxJS — Operators — cách pipeable operator nhận một Observable và trả về Observable mới mà không sửa source.
- RxJS — Observer — ba callback
next,error,completevà partial Observer. - RxJS — Subscription —
unsubscribe()và việc giải phóng tài nguyên của execution. - RxJS 7.x — tài liệu trong repository — nguồn versioned cho các guide và ví dụ chính thức.