Rxjs: Observable.combineLatest проти Observable.forkJoin


84

Просто цікаво, в чому різниця між Observable.combineLatestі Observable.forkJoin? Наскільки я бачу, єдина відмінність полягає forkJoinв тому, що спостережувані дані будуть завершені, а combineLatestповернуті найновіші значення.


4
Примітка: У rxjs6 + це тепер просто combineLatest()і forkJoin()функції, які створюють спостережуване. Вони роблять те саме, але синтаксис різний. Не плутайте, combineLatestз rxjs/operatorsякого оператора "труби". Якщо ви імпортуєте неправильний, ви отримаєте помилки.
Simon_Weaver

Відповіді:


126

Мало того, що forkJoinпотрібно, щоб усі вхідні спостережувані були заповнені, але він також повертає спостережуване, яке створює єдине значення, яке є масивом останніх значень, що створюються вхідними спостережуваними. Іншими словами, він чекає, поки останнє спостережуване введення не завершиться, а потім виробляє одне значення і завершує.

На відміну від цього, combineLatestповертає Observable, який виробляє нове значення кожного разу, коли вхідні спостережувані роблять, як тільки всі вхідні спостережувані створюють принаймні одне значення. Це означає, що він міг мати нескінченні значення і не заповнювати. Це також означає, що вхідні спостережувані дані не потрібно заповнювати перед створенням значення.


@GregL чи існує функція, яка працює як forkJoin, але працює також і при невдалих викликах http?
Туккан,

2
@Tukkan, я б зв'язав оператором, який відновлює помилки, до кожного http-спостережуваного, щоб ви визначили значення (значення), яке використовуватиметься для кожного запиту про помилку, а не шукати оператора, який поєднає кілька спостережуваних, які можуть помилитися ( Я не впевнений, що такий оператор існує). Оператори, які відновлюються після помилок, включають .catch(), .onErrorResumeNext()і, можливо .retry()(якщо виклик Http може періодично не спрацьовувати).
GregL

1
Тільки для уточнення, вони обидва виробляють масиви.
Simon_Weaver

@Simon_Weaver Не обов'язково. У випадку combineLatest(), ви можете надати функцію проекції, щоб вказати, як виробляти вихідне значення з останніх значень із вхідних спостережуваних. За замовчуванням, якщо ви не вказали його, ви отримаєте масив останніх випущених значень.
GregL

Кожна емісія з combLatest є масивом зібраних значень. Я просто хотів додати це, оскільки ви згадали лише масив для forkjoin. Отже, таким чином вони однакові. І так, завжди є тонкощі з RxJS, тому якщо я щось пропустив, ви можете пояснити, що ви мали на увазі.
Simon_Weaver

14

Також:

combLatest (...) запускає спостережувані послідовно, по черзі

combineLatestвнутрішньо використовує concat, що означає, що значення має бути отримано для кожного спостережуваного в масиві перед переходом до наступного.

// 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 (...) запускає спостережувані паралельно, одночасно

Якщо у вас є 3 спостережувані джерела, і кожному з них потрібно 5 секунд для запуску, тоді для запуску знадобиться 15 секунд combineLatest. Тоді як forkJoinвони виконують паралельно, то це займе 5 секунд.

Тож forkJoinпрацює дещо більше, як Promise.all(...)там, де наказ не виконується.

Розгляд помилок:

Якщо помилка будь-якої з спостережуваних помилка - з combineLatestнаступними не буде виконана, але з forkJoinусіма вони запущені. Тож combineLatestможе бути корисним виконати "послідовність" спостережуваних і зібрати результат разом.


Додаткова примітка: якщо спостережувані джерела вже `` запущені '' (передплачені чимось іншим), і ви використовуєте shareїх - тоді ви не побачите такої поведінки.

Ще більш досконала примітка: CombineLatest завжди надаватиме вам найсвіжіші дані з кожного джерела, тому, якщо одне із спостережуваних джерел видає кілька значень, ви отримаєте найновіше. Це не просто отримує одне значення для кожного джерела і переходить до наступного. Якщо вам потрібно переконатися, що ви отримуєте лише "наступний доступний елемент" для кожного спостережуваного джерела, ви можете додати .pipe(take(1))його до джерела спостережуваного, додавши його до вхідного масиву.


Дякуємо за розгляд помилок. Поводження з помилками досить важко зрозуміти у випадку кількох спостережуваних.
D Deshmane

2
Я вважаю , що ви неправильно зрозуміли , що concat()в combineLatest()коді роблять. Мені здається, що це Array.prototype.concatметод, а не concatметод RxJS . Припускаючи, що я маю рацію, тоді ця відповідь вводить в оману і неправильна, оскільки combineLatest()не виконує спостережувані по черзі послідовно. Він виконує їх паралельно, як і forkJoin(). Різниця полягає в тому, скільки значень вироблено і в тому, чи слід заповнити спостережувані джерела чи ні.
GregL

@GregL Array.concat не має сенсу для спостережуваних. Я абсолютно покладаюся на послідовний характер concat - головне, що слід зрозуміти, - це те, що ви не отримуєте жодних вихідних значень, поки всі вони не будуть виконані.
Simon_Weaver

Я мав на увазі цей код у зразку вихідного коду, який ви опублікували: [source].concat(observables)припускаючи, що це те, що ви мали на увазі, кажучи, що " combineLatestвнутрішньо використовує concat". Мені здається, ви плутаєте масив concat з RxJS concat. Останній дійсно виконує вхідні спостережувані послідовно, чекаючи, поки кожен не буде завершений. Але цим не користується combineLatest(), тобто цілком окремий оператор.
GregL

3
Я вірю, combineLatest()і forkJoin()обидва паралельно працюють. Запуск коду нижче дає близько 5000 для обох. 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));
Джеремі

12

forkПриєднуйтесь - Коли всі спостережувані завершені, значення з кожного.

об'єднатиОстанні - Коли будь-яке спостережуване випромінює значення, останнє значення від кожного.

Використання досить схоже, але не слід забувати скасувати підписку на combLatest на відміну від forkJoin .


1
якщо один, якщо запит не вдається, всі вкладені запити автоматично скасовуються, як я можу це вирішити?
Суніл Гарг,

1
@SunilGarg Ви повинні використовувати forkJoin або combLatest, якщо хочете отримати лише всі результати. Якщо вам не потрібні всі результати, вам слід користуватися підписками окремо.
Дмитро Гринько

Ви можете відповісти на це stackoverflow.com/questions/55558277/…
Суніл Гарг

Ви можете пояснити, чому потрібно скасувати підписку, на прикладі коду
Sunil Garg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.