Trailer

Ngày tháng cuối năm bận rộn, các anh chị em hăng say làm việc để đảm bảo kết quả đúng hạn đề ra. Thôi thì dành vài phút xem Trailer Mắt biếc version Lập trình viên cùng mình nhé, vừa giải trí vừa tích lũy kiến thức haaaa

*

♪ ♪ ♪ có chàng trai code lên cây ~~ ♪ ♪ ♪

Ngạn dev: – Nộiiii, sau này con muốn cưới Hà Lan làm vợ !

Nội Ngạn: – Con bé ấy dễ thương. Mắt nó đẹp như Mắt biếc. Nội sợ … con bé đó sau này sẽ khổ.

Bạn đang xem: Rxjs và reactive programming

Theo dòng thời gian, sau khi rời làng Đo Đo, Hà Lan lên thành phố đã xin vào một công ty phần mềm ở mảng Front-end Web. Và đúng như lời của nội, Hà Lan khổ thiệt ??.Mắt không còn biếc như xưa vì phải ngồi máy tính suy nghĩ quá nhiều ?))

Hà Lan: – Lập trình không đồng bộ chưa bao giờ dễ dàng cả !

Cũng chính vì vậy mà khi tiếp cận tới RxJS, Hà Lan cảm thấy hơi khoai mì. Chúng ta hãy cùng Hà Lan tìm hiểu xem RxJS là gì để giúp đời bớt khổ nhé

*

Reactive Programming

Trước khi đi vào RxJS, ta ghé qua khái niệm Reactive Programming:

Reactive programming is programming with asynchronous data streams

Reactive programming là phương pháp lập trình xoay quanh data streams và nó xử lý các vấn đề của asynchronous. Đừng hiểu lầm nhé, nó có thể xử lý với cả synchronous nữa.

Bạn có thể hình dung data streams như hình sau, với data được gửi đến trong suốt dòng thời gian của một stream (over time), giống như một array có các phần tử được gửi đến lần lượt theo thời gian:

*

Và chúng ta có thể coi mọi thứ là stream: single value, array, event.

*

Không những thế, khi thao tác với stream, chúng ta có thể có value, error, hay complete signals – Điều mà các API trước đây của các event trong Javascript còn thiếu, chúng có qua nhiều interface khác nhau cho các loại event khác nhau, Observable sinh ra để tổng quát hóa các interface đó lại.

RxJS

Như đã nói ở trên, RxJS giúp chúng ta có được tính chất reactive trong lập trình ứng dụng Javascript:

RxJS is a library for reactive programming using Observables, to make it easier to compose asynchronous or callback-based code.

Để giải thích cụ thể hơn, mình xin phép gói gọn nhỏ trong ReactJS chẳng hạn, chúng ta thường sử dụng Flux, Redux, MobX, MST để xử lý các luồng dữ liệu. Trong Redux, ta có một số midleware để xử lý vấn đề bất đồng bộ có thể kể đến như redux-saga, redux-thunk. Ở Saga và Thunk thì đôi khi khá nhiều biến làm phức tạp reducer lên khi ta chỉ muốn thực hiện một nhiệm vụ đơn giản.

Và đây chính là lúc ta tìm tới RxJS ??. RxJS cung cấp một số API dùng cho bất đồng bộ hiệu quả, từ xử lý luồng dữ liệu cho tới bắt lỗi và dừng request; điển hình có thể kể tới như Observables – hỗ trợ subscribe những event và thực hiện các RxJS operations tương ứng.

Có lẽ đó cũng là lý do Angular đi kèm với một dependency là RxJS giúp cho nó trở nên reactive, một ứng dụng Angular là một reactive system. Dễ thấy nhất ở đây chính là EventEmitter, hay Reactive Forms, bạn nào đã từng học Angular hẳn cũng không xa lạ gì với nó.

Hmmm…

Có vẻ như có khá nhiều thuật ngữ mới nhỉ, chúng ta sẽ làm rõ nó vào phần tiếp theo

RxJS Concepts

Một vài khái niệm cơ bản trong RxJS:

StreamProducerObservableObserverSubscriptionOperatorSubject

Cùng tìm hiểu chúng nào !

Stream

Định nghĩa

A stream is a sequence of data elements made available over time, as items on a conveyor belt being processed one at a time rather than in large batches.

Như vậy, theo một cách khác, cũng có thể hiểu rằng stream là một chuỗi các sự kiện đang diễn ra được sắp xếp theo thời gian.

Ví dụ

Số lần nhấp vào nút trong 1 giây. Vì vậy, tất cả các nhấp chuột sẽ được nhóm thành một luồng.

Trong RxJS, ta có thể tạo ra một stream từ một hoặc nhiều giá trị primitive, array, event, Promise, callback hay một vài kiểu cấu trúc dữ liệu khác.

Producer

Định nghĩa

A producer is the source of values for your observable

Ví dụ

Nó là bất kì kiểu dữ liệu nào đó cho phép ta lấy, truyền giá trị qua observer.next(value) như web socket, DOM events, iterator, array.

Observable

Định nghĩa

Observable is just a function that ties an observer to a producer and returns a function.

Rx.Observable class có chức năng tạo ra các observable từ các kiểu dữ liệu đã kể phía trên.

Một điểm lưu ý ở đây, Observable is inert. Nói vui điều này có nghĩa là, Observable sẽ cứ ngồi ì đấy cho tới khi ta subscribe, nó mới bắt đầu listen (khá giống với function-declaring và function-invoking nhỉ).

Ví dụ

// 1. From event: MouseEvent stream (new event is created every time a clicklet clicks = Rx.Observable.fromEvent(document, “click”);// 2. From array: streamconst array = ; let resultA = Rx.Observable.from(array); // 3. From Promise returned by fetch()let resultP = Rx.Observable.fromPromise(fetch(“http://haodev.wordpress.com/”));Phân loạiCold ObservableAn observable is cold if its underlying producer is created and activated during subscription (inside subscription)

Ví dụ

// Anything, subscribes `source`, gets its own instanceconst source = new Observable(observer => { const socket = new WebSocket(“http://haodev.wordpress.com/”); // …});Hot ObservableAn observable is hot if its underlying producer is either created or activated outside of subscription(outside subscription)

Ví dụ

// Anything, subscribes `source`, shares same instance, multicast to all subscriberconst socket = new WebSocket(“http://haodev.wordpress.com/”);const source = new Observable(observer => socket.addEventListener( “message”, e => observer.next(e)));Nhận xétObservable là hot hay cold phụ thuộc vào việc Producer được tham chiếu hay là tạo mới; Nếu như rơi vào cả 2 trường hợp, có lẽ, nó là warm observable (J4F)

Observer

Định nghĩa

In Reactive programming, Observer subscribes to an Observable. Then that observer reacts to whatever item or sequence of items the Observable emits.

Observer chính là param trong phương thức Observable.subscribe(observer).

Trong Observer gồm các callbacks tương ứng: next(), error() và complete()(không nhất thiết phải có đầy đủ tất cả) được gửi đến bởi Observable để xử lý các trạng thái tương ứng.

Ví dụ

// 1. Full callbacksconst observer = { next: x => console.log(“got value ” + x), error: err => console.error(“something wrong: ” + err), complete: () => console.log(“done”),};// 2. Just an next function (like then() in Promise)var observer = (x) => { console.log(“Completed”);}

Subscription

Định nghĩaSau khi Observable được tạo ra, nó sẽ chưa listen streams ngay lúc đó. Để invoke một Observable, chúng ta phải subscribe nó.

Xem thêm: Ẩm Thực Cajun Là Gì ? 4 điều Thú Vị Làm Nên ẩm Thực Cajun

Subscription được sinh ra khi ta subscribe Observable, nó thường dùng cho việc unsubscribe() Observable đó.

Ví dụ

let resultP = Rx.Observable.fromPromise(fetch(“http://haodev.wordpress.com/”));// With observer type 1resultP.subscribe(x => console.log(“got value ” + x))// With observer type 2resultP.subscribe(x => console.log(x), e => console.error(e));// With observer type 3resultP.subscribe({ next: x => console.log(“got value ” + x), error: err => console.error(“something wrong: ” + err), complete: () => console.log(“done”),});Khi ta không muốn listen stream đó nữa:

let subscriptionP = resultP.subscribe(observer);subscriptionP.unsubscribe();

Okayyy, sau khi đã biết Observable là gì rồi, ta cùng tìm hiểu sang Operator nào

Operator

Định nghĩa

Operator is also JUST FUNCTION.

Với Operator, ta vẫn có thể lập trình hàm với Observable:Operator là một pure function với Input là Observable và Output là một Observable khác, giữ được Observable Input không bị thay đổi.

Khi chúng ta subscribe()/unsubscribe() Observable Output thì đồng thời cũng subscribe()/unsubscribe() Observable Input.

Tương tự với array có rất nhiều các phương thức thao tác hỗ trợ, Observable cũng có đa dạng các Operators với nhiều mục đích khác nhau như create, filter, transform, combine, handle, utils, multicast, etc.

Ví dụ

// Get maximal value of number seriesRx.Observable.of(5, 4, 7, 2, 8).map(num => num*10).max().subscribe(x => console.log(x)); // 80Custom OperatorNgoài các built-in operators, ta cũng có thể viết ra các custom operators:

function multiplyByTen(input) { let output = Rx.Observable.create(function subscribe(observer) { input.subscribe({ next: v => observer.next(10 * v), error: err => observer.error(err), complete: () => observer.complete() }); }); return output;}const input = Rx.Observable.from();const output = multiplyByTen(input);output.subscribe(x => console.log(x)); // 10 20 30 40

Subject

Định nghĩaIn RxJS:Plain Observables are unicastSubject:Be a special type of Observable that allows values to be multicasted to many ObserverMaintain a registry of many listeners/subscriber.

Hmmm… nghe khoai mì nhỉ? Bảo sao Hà Lan rầu vậy?

Để xem nào !!! Hãy dẹp Subject qua một bên, tìm hiểu Unicast vs. Multicast là gì đã nhé

*

Unicast vs. Multicast

KeyUnicastMulticast
Def.A transmission/stream sends IP packets to a single recipient on a networkA transmission sends IP packets to a group of hosts on a network
Ex.Plain ObservableRxJs Subject, Promises
Giải thíchNếu ta subscribe nhiều lần với một observable gốc thì nó sẽ không được chia sẻ. Nghĩa là, mỗi lần subcribe là bạn đang tạo ra một observable mới.Có thể subscribe nhiều lần với obseravle gốc.
Hình dungBạn vào Youtube, mở video nào đó đã được thu sẵn và xem, nó play từ đầu đến cuối video. Một người khác vào xem, Youtube cũng sẽ phát từ đầu đến cuối như thế, hai người không có liên quan gì về thời gian hiện tại của video mà mình đang xem.2++ người vào xem video ở Youtube, nhưng video đó đang phát Live (trận bóng đá U23 hôm qua chẳng hạn :v). Lúc này, những người bắt đầu click vào xem sẽ có cùng một thời điểm của video đó.

Như vậy, Subject là một plain observable đặc biệt có khả năng thực hiện việc gửi dữ liệu đến nhiều Observers (multicasting).

Nhận xét

Mỗi Subject là một Observable

Với mỗi Subject, ta có thể subscribe vào nó, cung cấp cho nó một Observer và có thể nhận data tương ứng.

Mỗi Subject là một Observer

Bên trong Subject có chứa các method next(), error(), complete() tương ứng để có thể subscribe vào Observable chẳng hạn. Trường hợp cần gửi dữ liệu cho các Observers mà Subject đang quản lý, ta chỉ cần gọi hàm tương ứng của nó là được.

Notes

Tóm tắt lại thì, RxJS về bản chất là một thư viện nhỏ gọn trong Reactive Programming.Các tính năng khá phức tạp có thể được thực hiện dễ dàng với sự trợ giúp của Observables và các Operators.

Song, có một điểm cần lưu ý, khi subscribe một observable nhiều lần (đặc biệt là cold observable) thì vô hình chung sẽ tạo ra nhiều subscription tới một observable. Do đó, khi dùng tới Observable trong RxJS ta phải cực kì thận trọng tránh gây ra các vấn đề như memory leak, resource leak,…

Cá nhân mình cảm thấy RxJS là thư viện khá là khó khi mới tiếp cận; thế nếu như có thể hiểu được bản chất rồi thì RxJS có thể trở thành một trợ thủ đắc lực ^^

The more you use it, the more you can do with it.

The end

Yeahhhh, sau khi điểm qua các từ khóa trên đây thì Hà Lan đã hiểu hơn về Reactive Programming và RxJS Concepts rồi nè

Mong rằng bài viết này có thể giúp ích được cho các bạn mới tiếp cận tới RxJS như mình và cô Mắt biếc nhé. Từ đó Hà Lan cũng không còn phải code draft lên cây nữa rồi.

*

Cảm ơn các bạn đã đọc bài chia sẻ này. Tặng mình 1 upvote để có thêm động lực cho những bài viết sắp tới nha.

Xem thêm: Then Là Gì

Tham khảo thêm các bài viết về Technical tại đây ^^

Happy Coding !!!

Reference: Tiep Phan”s post, Personal Blog, Ben Lesh from Medium via post 1, post 2.

Chuyên mục: Hỏi Đáp