Tại sao Angular không phải là framework Observable bạn nghĩ
Khi nhiều lập trình viên nghe đến "observables", một framework thường xuất hiện trong tâm trí họ là Angular. Framework này đã được liên kết chặt chẽ với RxJS trong nhiều năm, được quảng cáo như là framework phản ứng (reactive) hàng đầu. Nhưng có một sự thật: Angular thực sự không hoạt động trong thế giới observable. Thay vào đó, nó liên tục khiến bạn phải chuyển đổi giữa việc quản lý các luồng RxJS ở một bên và mô hình phản ứng riêng của nó (như async pipes, signals) ở bên kia.
Khó khăn khi sử dụng Angular với RxJS
Điều này dẫn đến một số vấn đề:
- Bạn phải kết nối các async pipes khắp nơi.
- Bạn phải quản lý BehaviorSubjects bằng tay.
- Bạn luôn phải hủy đăng ký (unsubscribe).
- Giờ đây, với signals, bạn được yêu cầu học thêm một trừu tượng phản ứng khác.
Điều này không mượt mà, không tinh tế, và chắc chắn không phải trải nghiệm observable thuần khiết mà các lập trình viên RxJS mơ ước.
Giới thiệu Rimmel.js: Xây dựng trên Streams từ đầu
Hãy tưởng tượng một thư viện UI nơi bạn không cần hai mô hình. Nơi mà nguồn sự kiện và điểm đến dữ liệu chỉ liên kết với các luồng và UI của bạn chỉ là một đích đến khai báo cho dữ liệu của bạn. Đó là điều mà Rimmel.js được thiết kế để làm.
Đây không phải là Angular với một async pipe gắn thêm. Đây là lập trình hướng luồng (stream-oriented programming) — nơi mà observables không chỉ là những vị khách ở bàn tiệc, mà chính là cái bàn.
Và sự khác biệt là rất rõ ràng.
So sánh giữa Angular và Rimmel.js
Ví dụ về Counter
Phiên bản Angular
typescript
@Component({
selector: 'app-counter',
template: `
<button (click)="increment()">+</button>
<span>{{ count$ | async }}</span>
`,
})
export class CounterComponent {
private count = new BehaviorSubject(0);
count$ = this.count.asObservable();
increment() {
this.count.next(this.count.value + 1);
}
}
Phiên bản Rimmel.js
javascript
const Counter = () => {
const total = new BehaviorSubject(0).pipe(
scan(x => x + 1)
);
return rml`
<button onclick="${total}">
click me <span>${total}</span>
</button>
`;
};
Không có async pipes. Không có phương thức mệnh lệnh. Chỉ có các luồng, được kết nối gọn gàng và trực tiếp với UI.
Signals của Angular so với Observables của Rimmel
Những tín hiệu (signals) mà Angular gần đây đang thúc đẩy có vẻ hấp dẫn ở cái nhìn đầu tiên. Chúng hứa hẹn "phản ứng tinh vi" và "giảm thiểu tính toán lại". Nhưng thực tế lại như sau:
- Bạn giờ đây có hai mô hình phản ứng: signals và RxJS.
- Dữ liệu từ một observable vẫn phải được chuyển đổi thành một signal.
- Sự kiện từ UI của bạn vẫn phải đi qua các bước mệnh lệnh.
Kết quả là ứng dụng của bạn sẽ có logic phân tách: luồng cho công việc bất đồng bộ (async), signals cho việc hiển thị. Bạn học một mô hình phản ứng, sau đó liên tục chuyển đổi nó sang một mô hình khác. Điều này tạo ra sự phức tạp không cần thiết.
Với Rimmel.js, bạn không cần signals. Observables đã đủ mạnh mẽ, có thể xử lý cả dữ liệu bất đồng bộ và trạng thái phức tạp. Bằng cách loại bỏ lớp bổ sung, bạn chỉ cần giữ một mô hình tư duy duy nhất: luồng vào, luồng ra.
Kết quả là gì? Mã nguồn trông gọn gàng, nhẹ nhàng, trực tiếp và dễ dự đoán hơn.
Tại sao điều này quan trọng với các lập trình viên
Rimmel.js mang đến cho bạn:
- True first-class observables: Không có pipes, không có wrappers.
- Mã nguồn sạch hơn: Mọi phần của ứng dụng đều nói một ngôn ngữ: luồng.
- Tư duy tương lai: Lập trình hướng luồng mở rộng một cách thanh thoát với sự phức tạp.
- Sự quen thuộc ngay lập tức: Nếu bạn biết RxJS, bạn đã biết hầu hết về Rimmel.js.
Thay vì đấu tranh với nhiều hệ thống phản ứng, bạn có thể tập trung vào những gì quan trọng: phát triển tính năng, không phải boilerplate.
Kết luận
Angular có thể là framework mà bạn nghĩ đến khi nhắc đến "observables", nhưng thực tế là hỗ trợ observable của Angular rất nông. Nó khiến bạn phải liên tục chuyển đổi giữa async pipes, signals và RxJS — một gánh nặng trong việc chuyển đổi ngữ cảnh.
Rimmel.js đảo ngược điều đó. Bằng cách chấp nhận một mô hình hướng luồng, nó biến observables thành thứ tự nhiên trong ứng dụng của bạn. Kiến thức của bạn về RxJS không chỉ được chuyển giao — mà còn phát triển.
Tham khảo thêm
|---|---|
||Lập trình hướng luồng: giới thiệu|
||Tạo Web Components chỉ với một hàm đơn giản|
||Từ callbacks đến callforwards: phản ứng trở nên đơn giản?|