Rxjs: Observable.combineLatest so với Observable.forkJoin


84

Chỉ cần tự hỏi sự khác biệt giữa Observable.combineLatestvà là Observable.forkJoingì? Theo như tôi thấy, sự khác biệt duy nhất là forkJoinmong đợi các Observables được hoàn thành, trong khi combineLatesttrả về các giá trị mới nhất.


4
Lưu ý: Trong rxjs6 + những bây giờ chỉ combineLatest()forkJoin()chức năng mà tạo ra một quan sát được. Họ làm giống nhau, nhưng cú pháp khác nhau. Đừng nhầm lẫn combineLatesttừ rxjs/operatorsđó là toán tử 'có thể phân phối'. Nếu bạn nhập sai, bạn sẽ gặp lỗi.
Simon_Weaver

Câu trả lời:


126

Không chỉ forkJoinyêu cầu hoàn thành tất cả các quan sát đầu vào mà còn trả về một có thể quan sát tạo ra một giá trị duy nhất là mảng các giá trị cuối cùng được tạo ra bởi các quan sát đầu vào. Nói cách khác, nó đợi cho đến khi đầu vào cuối cùng có thể quan sát được hoàn thành, sau đó tạo ra một giá trị duy nhất và hoàn thành.

Ngược lại, combineLatesttrả về một Quan sát được tạo ra một giá trị mới mỗi khi các quan sát đầu vào thực hiện, khi tất cả các quan sát đầu vào đã tạo ra ít nhất một giá trị. Điều này có nghĩa là nó có thể có giá trị vô hạn và có thể không hoàn thành. Điều đó cũng có nghĩa là các dữ liệu quan sát đầu vào không cần phải hoàn thành trước khi tạo ra một giá trị.


@GregL có một chức năng hoạt động giống như forkJoin nhưng cũng sẽ hoạt động với các lệnh gọi http không thành công không?
Tukkan

2
@Tukkan, tôi sẽ xâu chuỗi một toán tử khôi phục từ lỗi thành từng http có thể quan sát được, để bạn xác định (các) giá trị để sử dụng cho mỗi yêu cầu khi có lỗi, thay vì tìm kiếm một toán tử sẽ kết hợp nhiều có thể quan sát có thể bị lỗi (tôi 'tôi không chắc một toán tử như vậy tồn tại). Các nhà khai thác vàng hồi phục từ lỗi bao gồm .catch(), .onErrorResumeNext()và có thể .retry()(nếu cuộc gọi Http có thể thất bại liên tục).
GregL

1
Chỉ cần làm rõ, cả hai đều sản xuất mảng.
Simon_Weaver

@Simon_Weaver Không nhất thiết. Trong trường hợp combineLatest(), bạn có thể cung cấp một hàm chiếu để chỉ định cách tạo ra giá trị đầu ra từ các giá trị mới nhất từ ​​các vật quan sát đầu vào. Theo mặc định, nếu bạn không chỉ định một, bạn sẽ nhận được một mảng các giá trị mới nhất được phát ra.
GregL

Mỗi phát xạ từ connectLatest là một mảng các giá trị được thu thập. Tôi chỉ muốn thêm điều đó vì bạn chỉ đề cập đến mảng cho forkjoin. Vì vậy, theo cách đó chúng giống nhau. Và vâng, luôn có sự tinh tế với RxJS vì vậy nếu tôi bỏ sót điều gì đó, bạn có thể làm rõ ý của bạn.
Simon_Weaver

14

Cũng thế:

connectLatest (...) chạy các có thể quan sát theo trình tự, từng cái một

combineLatestsử dụng nội bộ concat, có nghĩa là một giá trị phải được lấy cho mỗi có thể quan sát trong mảng trước khi chuyển sang phần tiếp theo.

// partial source of static combineLatest (uses the rxjs/operators combineLatest internally):
// If you're using typescript then the output array will be strongly typed based on type inference
return function (source) { return source.lift.call(from_1.from([source].concat(observables)), 
                           new combineLatest_1.CombineLatestOperator(project)); };

forkJoin (...) chạy song song các có thể quan sát, đồng thời

Nếu bạn có 3 nguồn quan sát và mỗi nguồn mất 5 giây để chạy thì sẽ mất 15 giây combineLatestđể chạy. Trong khi forkJoinchúng thực hiện song song nên sẽ mất 5 giây.

Vì vậy, forkJoinhoạt động giống như Promise.all(...)nơi lệnh không được thực thi.

Cân nhắc xử lý lỗi:

Nếu bất kỳ lỗi nào có thể quan sát được - với combineLatestnhững lỗi tiếp theo sẽ không được thực thi, nhưng forkJointất cả chúng đều đang chạy. Vì vậy, combineLatestcó thể hữu ích để thực hiện một 'chuỗi' các vật thể quan sát và thu thập tất cả kết quả cùng nhau.


Lưu ý nâng cao: Nếu các nguồn có thể quan sát đã 'đang chạy' (được đăng ký bởi thứ khác) và bạn đang sử dụng sharechúng - thì bạn sẽ không thấy hành vi này.

Lưu ý nâng cao hơn nữa: CombineLatest sẽ luôn cung cấp cho bạn thông tin mới nhất từ ​​mỗi nguồn, vì vậy nếu một trong các nguồn có thể quan sát phát ra nhiều giá trị, bạn sẽ nhận được giá trị mới nhất. Nó không chỉ nhận một giá trị duy nhất cho mỗi nguồn và chuyển sang nguồn tiếp theo. Nếu bạn cần đảm bảo rằng bạn chỉ nhận được 'mục có sẵn tiếp theo' cho mỗi nguồn có thể quan sát được, bạn có thể thêm .pipe(take(1))vào nguồn có thể quan sát khi bạn thêm nó vào mảng đầu vào.


Cảm ơn vì đã cân nhắc xử lý lỗi. Việc xử lý lỗi khá khó hiểu trong trường hợp có nhiều vật quan sát.
D Deshmane

2
Tôi tin rằng bạn đã hiểu sai những gì concat()trong combineLatest()mã đang làm. Đối với tôi, nó giống như Array.prototype.concatphương pháp, không phải concatphương pháp RxJS . Giả sử tôi đúng, thì câu trả lời này gây hiểu lầm và không chính xác, vì combineLatest()không thực thi từng cái một, theo trình tự. Nó thực hiện chúng song song, giống như forkJoin(). Sự khác biệt là có bao nhiêu giá trị được tạo ra và liệu các nguồn quan sát có phải hoàn thành hay không.
GregL

@GregL Array.concat là vô nghĩa với các đối tượng quan sát. Tôi hoàn toàn dựa vào bản chất tuần tự của concat - điều quan trọng cần hiểu là bạn không nhận được bất kỳ giá trị đầu ra nào cho đến khi tất cả chúng đã được thực thi.
Simon_Weaver

Tôi đã đề cập đến mã này trong mã nguồn mẫu mà bạn đã đăng [source].concat(observables):, giả sử đó là ý của bạn khi nói rằng " combineLatestsử dụng nội bộ concat". Đối với tôi, có vẻ như bạn đang nhầm lẫn giữa kết hợp mảng với RxJS concat. Cái thứ hai thực sự thực thi các quan sát đầu vào theo trình tự, đợi cho đến khi hoàn thành mỗi cái. Nhưng điều đó không được sử dụng bởi combineLatest(), đó là một toán tử riêng biệt hoàn toàn.
GregL

3
Tôi tin combineLatest()forkJoin()cả hai đều chạy song song. Chạy đoạn mã dưới đây cho ra khoảng 5000 cho cả hai. const start = new Date().getTime(); combineLatest([of(null).pipe(delay(5000)), of(null).pipe(delay(5000)), of(null).pipe(delay(5000))]).subscribe(() => console.log(new Date().getTime() - start)); forkJoin([of(null).pipe(delay(5000)), of(null).pipe(delay(5000)), of(null).pipe(delay(5000))]).subscribe(() => console.log(new Date().getTime() - start));
Jeremy

12

forkJoin - Khi tất cả các khả năng quan sát hoàn thành, hãy phát ra giá trị phát ra cuối cùng từ mỗi.

connectLatest - Khi bất kỳ giá trị nào có thể quan sát được phát ra một giá trị, hãy phát ra giá trị mới nhất từ ​​mỗi giá trị.

Cách sử dụng khá giống nhau, nhưng bạn không nên quên hủy đăng ký kết hợp với forkJoin .


1
nếu một nếu yêu cầu không thành công, tất cả các yêu cầu lồng nhau sẽ tự động bị hủy, làm cách nào để giải quyết vấn đề này?
Sunil Garg

1
@SunilGarg Bạn nên sử dụng forkJoin hoặc connectLatest nếu bạn chỉ muốn nhận tất cả kết quả. Nếu bạn không quan tâm đến tất cả các kết quả, bạn nên sử dụng các đăng ký riêng.
Dmitry Grinko

bạn có thể trả lời điều này stackoverflow.com/questions/55558277/…
Sunil Garg

bạn có thể giải thích lý do tại sao cần hủy đăng ký với mã ví dụ
Sunil Garg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.