Verschil tussen forkJoin en combineLatest
Bij het combineren van meerdere Observables in RxJS zijn forkJoin en combineLatest de meest gebruikte Creation Functions. De twee gedragen zich echter heel verschillend en als ze niet correct worden gebruikt, zullen ze niet de verwachte resultaten opleveren.
Deze pagina vergelijkt de verschillen tussen de twee grondig met illustraties en praktische voorbeelden om duidelijk te maken welke je het beste kunt gebruiken.
Conclusie: het verschil tussen forkJoin en combineLatest
| Kenmerk | forkJoin | combineLatest |
|---|---|---|
| Emissie-timing | Slechts één keer na voltooiing van alle | Bij elke update van een waarde |
| Geëmitteerde waarde | De laatste waarde van elke Observable | De meest recente waarde van elke Observable |
| Voltooiingsvoorwaarde | Alle Observables voltooid | Alle Observables voltooid |
| Hoofdgebruik | Parallelle API-acquisitie, initiële laden | Formuliermonitoring, realtime synchronisatie |
| Oneindige stream | ❌ Niet bruikbaar (wordt niet voltooid) | ✅ Bruikbaar (emitteert waarden zonder voltooiing) |
TIP
Makkelijk te onthouden
forkJoin= «vertrek slechts één keer als iedereen aanwezig is» (vergelijkbaar met Promise.all)combineLatest= «meld de laatste status elke keer als iemand beweegt»
De verschillen in gedrag met illustraties begrijpen
Gedrag van forkJoin
Punt: wacht tot alle Observables complete zijn en geef alleen de laatste waarde eenmaal uit.
Gedrag van combineLatest
Punt: nadat alle Observables hun eerste waarde hebben uitgegeven, blijven ze de meest recente combinatie uitgeven elke keer dat een van hen wordt bijgewerkt.
Verschillen in de tijdlijn
Praktische vergelijking: controleer gedrag met dezelfde gegevensbron
Pas forkJoin en combineLatest toe op dezelfde Observable en controleer de verschillen in uitvoer.
import { forkJoin, combineLatest, interval, take, map } from 'rxjs';
// uitvoergebied aanmaken
const output = document.createElement('div');
output.innerHTML = '<h3>Vergelijking forkJoin vs combineLatest:</h3>';
document.body.appendChild(output);
// Maak 2 Observables aan
const obs1$ = interval(1000).pipe(
take(3),
map(i => `A${i}`)
);
const obs2$ = interval(1500).pipe(
take(2),
map(i => `B${i}`)
);
// Resultaatweergavegebied voor forkJoin
const forkJoinResult = document.createElement('div');
forkJoinResult.innerHTML = '<h4>forkJoin:</h4><div id="forkjoin-output">wachten...</div>';
output.appendChild(forkJoinResult);
// Resultaatweergavegebied voor combineLatest
const combineLatestResult = document.createElement('div');
combineLatestResult.innerHTML = '<h4>combineLatest:</h4><div id="combinelatest-output"></div>';
output.appendChild(combineLatestResult);
// forkJoin:na voltooiing van alle1geeft slechts één keer uit
forkJoin([obs1$, obs2$]).subscribe(result => {
const el = document.getElementById('forkjoin-output');
if (el) {
el.textContent = `uitgifte: [${result.join(', ')}]`;
el.style.color = 'green';
el.style.fontWeight = 'bold';
}
});
// combineLatest:geeft uit bij elke waarde-update
const combineOutput = document.getElementById('combinelatest-output');
combineLatest([obs1$, obs2$]).subscribe(result => {
if (combineOutput) {
const item = document.createElement('div');
item.textContent = `uitgifte: [${result.join(', ')}]`;
combineOutput.appendChild(item);
}
});Uitvoerresultaat:
forkJoin: geeft[A2, B1]slechts één keer uit na ongeveer 3 secondencombineLatest: geeft 4 keer uit vanaf ongeveer 1,5 s (bijv.[A0, B0]→[A1, B0]→[A2, B0]→[A2, B1])
NOTE
De volgorde van uitgifte van
combineLatesthangt af van de planning van de timer en kan variëren afhankelijk van de omgeving. Belangrijk is dat «een waarde wordt uitgegeven elke keer dat een van hen wordt bijgewerkt». In het bovenstaande voorbeeld wordt 4 keer uitgegeven, maar de volgorde kan veranderen, bijvoorbeeld[A1, B0]→[A1, B1].
Welke moet worden gebruikt (gevalspecifieke gids)
Gevallen waarin forkJoin moet worden gebruikt
1. Parallelle acquisitie van meerdere API's
Wanneer je de gegevens wilt verwerken nadat alle gegevens beschikbaar zijn.
import { forkJoin } from 'rxjs';
import { ajax } from 'rxjs/ajax';
// gelijktijdig gebruikersinfo en instellingen ophalen
forkJoin({
user: ajax.getJSON('/api/user/123'),
settings: ajax.getJSON('/api/settings'),
notifications: ajax.getJSON('/api/notifications')
}).subscribe(({ user, settings, notifications }) => {
// scherm renderen nadat alle gegevens klaar zijn
renderDashboard(user, settings, notifications);
});2. Batchgegevensverzameling bij initiële laden
Verzamel alle benodigde stamgegevens in één keer bij de start van de toepassing.
import { forkJoin } from 'rxjs';
import { ajax } from 'rxjs/ajax';
function loadInitialData() {
return forkJoin({
categories: ajax.getJSON('/api/categories'),
countries: ajax.getJSON('/api/countries'),
currencies: ajax.getJSON('/api/currencies')
});
}WARNING
forkJoinkan niet worden gebruikt met Observables die niet voltooid worden (bijv.interval, WebSocket, event streams). Als het niet voltooid wordt, blijft het wachten.
Gevallen waarin combineLatest moet worden gebruikt
1. Realtime monitoring van formulierinvoer
Combineer meerdere invoerwaarden om validatie en weergave bij te werken.
import { combineLatest, fromEvent } from 'rxjs';
import { map, startWith } from 'rxjs';
const name$ = fromEvent(nameInput, 'input').pipe(
map(e => (e.target as HTMLInputElement).value),
startWith('')
);
const email$ = fromEvent(emailInput, 'input').pipe(
map(e => (e.target as HTMLInputElement).value),
startWith('')
);
const age$ = fromEvent(ageInput, 'input').pipe(
map(e => parseInt((e.target as HTMLInputElement).value) || 0),
startWith(0)
);
// validatie uitvoeren bij elke invoerverandering
combineLatest([name$, email$, age$]).subscribe(([name, email, age]) => {
const isValid = name.length > 0 && email.includes('@') && age >= 18;
submitButton.disabled = !isValid;
});2. Realtime synchronisatie van meerdere streams
Geïntegreerde weergave van sensorgegevens en status.
import { combineLatest, interval } from 'rxjs';
import { map } from 'rxjs';
const temperature$ = interval(2000).pipe(map(() => 20 + Math.random() * 10));
const humidity$ = interval(3000).pipe(map(() => 40 + Math.random() * 30));
const pressure$ = interval(2500).pipe(map(() => 1000 + Math.random() * 50));
combineLatest([temperature$, humidity$, pressure$]).subscribe(
([temp, humidity, pressure]) => {
updateDashboard({ temp, humidity, pressure });
}
);3. Combinatie van filtervoorwaarden
Voer een zoekopdracht uit elke keer dat meerdere filtervoorwaarden veranderen.
import { combineLatest, BehaviorSubject } from 'rxjs';
import { debounceTime, switchMap } from 'rxjs';
const searchText$ = new BehaviorSubject('');
const category$ = new BehaviorSubject('all');
const sortOrder$ = new BehaviorSubject('asc');
combineLatest([searchText$, category$, sortOrder$]).pipe(
debounceTime(300),
switchMap(([text, category, sort]) =>
fetchProducts({ text, category, sort })
)
).subscribe(products => {
renderProductList(products);
});Stroomdiagram voor gebruik
Veelvoorkomende fouten en oplossingen
Fout 1: forkJoin gebruiken voor een Observable die niet voltooid wordt
// ❌ dit wordt nooit uitgegeven
forkJoin([
interval(1000), // voltooit niet
ajax.getJSON('/api/data')
]).subscribe(console.log);
// ✅ takevoltooien met combineLatestgebruiken
forkJoin([
interval(1000).pipe(take(5)), // 5voltooit in
ajax.getJSON('/api/data')
]).subscribe(console.log);Fout 2: geen initiële waarde in combineLatest
// ❌ name$tot B voor het eerst uitgeeftemail$zelfs met waarden wordt niets uitgegeven
combineLatest([name$, email$]).subscribe(console.log);
// ✅ startWithstel initiële waarde in met
combineLatest([
name$.pipe(startWith('')),
email$.pipe(startWith(''))
]).subscribe(console.log);Samenvatting
| Selectiecriterium | forkJoin | combineLatest |
|---|---|---|
| Eenmalige verwerking wanneer alle klaar zijn | ✅ | ❌ |
| Verwerking bij elke waardeverandering | ❌ | ✅ |
| Stream die niet voltooid wordt | ❌ | ✅ |
| Promise.all-achtig gebruik | ✅ | ❌ |
| Realtime synchronisatie | ❌ | ✅ |
IMPORTANT
Gebruiksprincipe
- forkJoin: «slechts één keer wanneer iedereen aanwezig is» → parallelle API-acquisitie, initiële laden
- combineLatest: «update elke keer als iemand beweegt» → formuliermonitoring, realtime UI
Gerelateerde pagina's
- forkJoin - Gedetailleerde uitleg over forkJoin
- combineLatest - Gedetailleerde uitleg over combineLatest
- zip - Overeenkomstige waarden paren
- merge - Meerdere Observables parallel uitvoeren
- withLatestFrom - Alleen de hoofdstream is trigger