RxJS Combination Operators - quan1997ap/angular-app-note GitHub Wiki
1. forkJoin()
- forkJoin() chỉ emit khi các children Observables complete. Nếu như 1 trong số các children Observables không complete, forkJoin() sẽ không bao giờ emit.
- forkJoin() sẽ throw error khi 1 trong các children Observables throw error, và giá trị của các children Observables đã complete khác sẽ bị nuốt mất nếu như các bạn không xử lý error hợp lý.
2. combineLatest()
- Qua ví dụ, các bạn cũng có thể thấy là combineLatest(), sau lần emit đầu tiên của các children Observables, thì sẽ emit giá trị mới nhất của child Observable đang emit + giá trị gần nhất của các children Observables đã emit.
- Cũng qua ví dụ, các bạn có thể thấy là Observable thứ 2 {2} (interval(1000)) bị nuốt mất 2 giá trị đầu tiên là 0 và 1 vì {2} đã emit với tần suất nhanh hơn là Observable có khoảng thời gian lâu nhất {3}. Đây là điều các bạn cần lưu ý để có thể tránh hiện tượng racing condition.
- combineLatest() sẽ complete khi tất cả children Observables complete.
- combineLatest() sẽ không bao giờ complete nếu như 1 trong số các children Observables không bao giờ complete.
- combineLatest() sẽ throw error nếu như 1 trong số các children Observables throw error và giá trị của các children Observables đã emit khác sẽ bị nuốt (behavior này giống với forkJoin())
3.zip()
4.concat()
- concat() sẽ hoạt động tương tự cho LẦN LƯỢT từng children Observables cho đến khi không còn Observable nào thì concat() sẽ complete.
- Nếu 1 Observables error, concat() sẽ error ngay lặp tức và chuỗi Observable phía sau sẽ bị bỏ qua.
- Concat có tính thứ tự, đợi cái trước xong mới bắt đầu cái tiếp theo
5.merge()
- Ở đây, merge() emit luôn 1,2,3 rồi mới tới 4,5,6 và không hề quan tâm đến thứ tự mà các children Observables này được truyền vào
- merge() sẽ subscribe vào tất cả (phụ thuộc vào tham số concurrent nếu được truyền vào) các children Observables và sẽ:
- emit giá trị mà bất cứ Observable nào emit.
- throw error nếu 1 trong children Observables throw error
- complete khi và chỉ khi tất cả children Observables complete.
6. MergeMap
Link: https://viblo.asia/p/su-khac-biet-giua-mergemap-va-switchmap-trong-rxjs-L4x5xaAwKBM
mergeMap cho phép những lần thực thi của executor của observable đích mỗi khi observable đích được subscribe(bởi mergeMap) được chạy song song với nhau.
VD: timer(2000) is API call
import { fromEvent, timer } from "rxjs";
import { mergeMap } from "rxjs/operators";
fromEvent(document, "click")
.pipe(mergeMap(_ => timer(2000)))
.subscribe(() => {
console.log("data");
});
Giải thích ví dụ:
Tạo một observable từ event click của document, observable này sẽ emit ra một gói data chứa thông tin của event click của document mỗi khi người dụng click vào trình duyệt.
Khi user click vào trình duyệt, observable được tạo từ: fromEvent(document, "click") sẽ emit ra một gói data _(các bạn có thể xóa _ nếu không dùng). và ngay khi mergeMap nhận được _, nó sẽ tự động subscribe observable timer(2000).
Điều thú vị về mergeMap đó là nó cho phép executor của observable đích được chạy song song. Nếu các bạn click vào trình duyệt 3 lần cùng lúc với nhau thì sau 2s, console của trình duyệt sẽ in ra 3 string "data".
8. switchMap
Giống với mergeMap, switchMap sẽ subscribe observable đích mỗi khi nó nhận được các gói data từ observable gốc. Tuy nhiên, trước khi nó subscribe observable đích, nó sẽ cancel lần thực thi cuối của executor của observable đích(nếu có).
VD: timer(2000) is API call
import { fromEvent, timer } from "rxjs";
import { switchMap } from "rxjs/operators";
fromEvent(document, "click")
.pipe(switchMap(_ => timer(2000)))
.subscribe(() => {
console.log("data");
});
Giải thích ví dụ:
Khi user click vào trình duyệt, observable được tạo từ: fromEvent(document, "click") sẽ emit ra một gói data _(các bạn có thể xóa _ nếu không dùng).
Và ngay khi switchMap nhận được _, nó sẽ kiểm tra xem timer(2000) đã được subscribe bới switchMap trước đó hay chưa.
Nếu timer(2000) đã được subscribe hoặc lần thực thi cuối của executor của timer(2000) vẫn chưa hoàn thành thì switchMap sẽ cancel việc thực thi của executor của timer(2000) ở lần subscribe cuối. Sau đó, nó sẽ subscribe observable timer(2000).
Nếu các bạn click vào trình duyệt 3 lần cùng lúc với nhau thì sau 2s, console của trình duyệt trong ví dụ này sẽ chỉ in ra 1 string "data" mà thôi(vì switchMap chỉ cho phép lần thực thi mới nhất của executor của timer(2000) được chạy).
6+7: So sanh Switchmap vs Merge map
import { fromEvent, timer, of } from "rxjs";
import { mergeMap,switchMap, delay, tap, map } from "rxjs/operators";
/**
click web view xem chi tiet
Cac API chay song song, bat dong bo. Ket qua tra ve theo thu tu cua api
*/
let time = 10;
fromEvent(document, "click")
.pipe(
tap( () => { time = time - 3; console.log(time); } ),
mergeMap(
(data) => of(time).pipe(
delay(time * 1000),
map( (time) => { return time} )
)
)
)
.subscribe((data) => {
console.log("data", data);
});
8. Concat map
Cac request thuc hien tuan tu, cai truoc complete thi cai sau moi bat dau
import { fromEvent, timer, of } from "rxjs";
import { concatMap, mergeMap,switchMap, delay, tap, map } from "rxjs/operators";
/**
click web view xem chi tiet
Cac API chay song song, bat dong bo. Ket qua tra ve theo thu tu cua api
*/
let time = 18;
fromEvent(document, "click")
.pipe(
tap( () => {
time = time - 5;
console.log('click', time);
}),
map( () => time ),
concatMap(
(data) => of(data).pipe(
tap( () => { console.log( data); } ),
delay(time * 1000)
)
)
)
.subscribe((data) => {
console.log("data", data);
});