Skip to content

windowCount - Splits Observable op gespecificeerd aantal ​

De windowCount operator verdeelt uitgezonden waarden in nieuwe Observables voor elk gespecificeerd aantal. Terwijl bufferCount een array retourneert, retourneert windowCount een Observable<T>, waardoor extra operators op elk venster kunnen worden toegepast.

🔰 Basissyntax en gebruik ​

ts
import { interval } from 'rxjs';
import { windowCount, mergeAll } from 'rxjs';

// Geef waarden elke 100ms uit
const source$ = interval(100);

source$.pipe(
  windowCount(5),
  mergeAll() // Plat elke venster
).subscribe(value => {
  console.log('Waarde in venster:', value);
});

// Uitvoer:
// Waarde in venster: 0
// Waarde in venster: 1
// Waarde in venster: 2
// Waarde in venster: 3
// Waarde in venster: 4
// (Nieuw venster start)
// Waarde in venster: 5
// ...
  • Een nieuw venster (Observable) wordt gemaakt voor elke 5 waarden.
  • Het is uniek doordat het verdeelt op een aantal basis.

🌐 RxJS Officiële Documentatie - windowCount

💡 Typische gebruikspatronen ​

  • Aggregaatverwerking voor elk vast aantal
  • Batch verzending van data (verschillende verwerking voor elk venster)
  • Paginaverwerking
  • Bereken statistieken per venster

🔍 Verschil met bufferCount ​

OperatorUitvoerGebruiksscenario
bufferCountArray (T[])Gegroepeerde waarden samen verwerken
windowCountObservable<T>Verschillende streamverwerking voor elke groep
ts
import { interval } from 'rxjs';
import { bufferCount, windowCount, mergeAll } from 'rxjs';

const source$ = interval(100);

// bufferCount - Uitvoer als array
source$.pipe(
  bufferCount(5)
).subscribe(values => {
  console.log('Buffer (array):', values);
  // Uitvoer: Buffer (array): [0, 1, 2, 3, 4]
});

// windowCount - Uitvoer als Observable
source$.pipe(
  windowCount(5)
).subscribe(window$ => {
  console.log('Venster (Observable):', window$);
  window$.subscribe(value => {
    console.log('  Waarde in venster:', value);
  });
});

🧠 Praktisch codevoorbeeld 1: Som per venster ​

Dit is een voorbeeld van het berekenen van de som van elke 5 waarden.

ts
import { interval } from 'rxjs';
import { windowCount, map, mergeAll, reduce } from 'rxjs';

// Maak uitvoergebied
const output = document.createElement('div');
output.innerHTML = '<h3>Som elke 5 waarden</h3>';
document.body.appendChild(output);

const source$ = interval(200);

let windowNumber = 0;

source$.pipe(
  windowCount(5),
  map(window$ => {
    const current = ++windowNumber;
    console.log(`Venster ${current} gestart`);

    // Bereken som voor elk venster
    return window$.pipe(
      reduce((sum, value) => sum + value, 0),
      map(sum => ({ windowNum: current, sum }))  // Voeg vensternummer toe
    );
  }),
  mergeAll()
).subscribe(result => {
  const div = document.createElement('div');
  div.textContent = `Venster ${result.windowNum} som: ${result.sum}`;
  output.appendChild(div);
});

// Uitvoer:
// Venster 1 som: 10  (0+1+2+3+4)
// Venster 2 som: 35  (5+6+7+8+9)
// Venster 3 som: 60  (10+11+12+13+14)

🎯 Praktisch codevoorbeeld 2: Startindex specificeren ​

U kunt een startindex specificeren met het tweede argument. Dit maakt overlappende vensters.

ts
import { range } from 'rxjs';
import { windowCount, mergeMap, toArray } from 'rxjs';

// Geef waarden van 0 tot 9 uit
range(0, 10).pipe(
  windowCount(3, 2), // 3 items elk, start verschoven met 2
  mergeMap(window$ => window$.pipe(toArray()))
).subscribe(values => {
  console.log('Venster:', values);
});

// Uitvoer:
// Venster: [0, 1, 2]
// Venster: [2, 3, 4]    ← Gestart verschoven met 2 (vanaf 2)
// Venster: [4, 5, 6]    ← Gestart verschoven met 2 (vanaf 4)
// Venster: [6, 7, 8]
// Venster: [8, 9]       ← Laatste 2 items

Startindex operatiepatronen ​

ts
// windowCount(bufferSize, startBufferEvery)

windowCount(3, 3) // Continu (standaard): [0,1,2], [3,4,5], [6,7,8]
windowCount(3, 2) // Overlap: [0,1,2], [2,3,4], [4,5,6]
windowCount(3, 4) // Met gat: [0,1,2], [4,5,6], [8,9,10]

🎯 Praktisch voorbeeld: Verschillende verwerking voor elk venster ​

ts
import { interval } from 'rxjs';
import { windowCount, map, mergeAll, take } from 'rxjs';

const source$ = interval(100);
let windowNumber = 0;

source$.pipe(
  windowCount(5),
  map(window$ => {
    const current = ++windowNumber;

    if (current % 2 === 0) {
      // Even vensters: Krijg alleen eerste 2 items
      console.log(`Venster ${current}: Krijg eerste 2 items`);
      return window$.pipe(take(2));
    } else {
      // Oneven vensters: Krijg alles
      console.log(`Venster ${current}: Krijg alles`);
      return window$;
    }
  }),
  mergeAll()
).subscribe(value => {
  console.log(`Waarde: ${value} (Venster ${windowNumber})`);
});

🧠 Praktisch codevoorbeeld 3: Paginatie-achtige verwerking ​

ts
import { from } from 'rxjs';
import { windowCount, mergeMap, toArray, map } from 'rxjs';

// Data van 1-20
const data$ = from(Array.from({ length: 20 }, (_, i) => i + 1));

// Pagineer met 5 items
data$.pipe(
  windowCount(5),
  mergeMap((window$, index) => {
    const pageNumber = index + 1;
    return window$.pipe(
      toArray(),
      map(items => ({ page: pageNumber, items }))
    );
  })
).subscribe(page => {
  console.log(`Pagina ${page.page}:`, page.items);
});

// Uitvoer:
// Pagina 1: [1, 2, 3, 4, 5]
// Pagina 2: [6, 7, 8, 9, 10]
// Pagina 3: [11, 12, 13, 14, 15]
// Pagina 4: [16, 17, 18, 19, 20]

⚠️ Opmerkingen ​

1. Venster abonnementbeheer ​

Elk venster is een onafhankelijke Observable en moet expliciet worden geabonneerd.

ts
source$.pipe(
  windowCount(5)
).subscribe(window$ => {
  // Waarden stromen niet tenzij u abonneert op het venster zelf
  window$.subscribe(value => {
    console.log('Waarde:', value);
  });
});

Of gebruik mergeAll(), concatAll(), switchAll(), etc. om te plat te maken.

2. Laatste venster ​

Bij voltooiing van de bron Observable wordt het laatste venster uitgevoerd zelfs als het minder dan het gespecificeerde aantal items bevat.

ts
import { of } from 'rxjs';
import { windowCount, mergeMap, toArray } from 'rxjs';

of(1, 2, 3, 4, 5, 6, 7).pipe(
  windowCount(3),
  mergeMap(window$ => window$.pipe(toArray()))
).subscribe(values => {
  console.log('Venster:', values);
});

// Uitvoer:
// Venster: [1, 2, 3]
// Venster: [4, 5, 6]
// Venster: [7]  ← Slechts 1 item

3. Geheugengebruik door startindex ​

Als startBufferEvery kleiner is dan bufferSize (overlap), zullen meerdere vensters tegelijk actief zijn, wat het geheugengebruik verhoogt.

ts
// Overlap: Maximaal 2 vensters gelijktijdig actief
windowCount(5, 3)

// Tegenmaatregel: Beperk met take() indien nodig
source$.pipe(
  take(100), // Maximaal 100 items
  windowCount(5, 3)
)

🆚 Vergelijking van window operators ​

OperatorTiming van afbakeningGebruiksscenario
windowAndere Observable zendt uitEvent-gedreven partitionering
windowTimeVast tijdsintervalTijd-gebaseerde partitionering
windowCountVast aantalAantal-gebaseerde partitionering
windowToggleStart en eind ObservablesDynamische start/eind controle
windowWhenDynamische sluitconditieVerschillende eindconditie per venster

📚 Gerelateerde operators ​

  • bufferCount - Verzamel waarden als array (array versie van windowCount)
  • window - Splits venster op timing van verschillende Observable
  • windowTime - Tijd-gebaseerde venstersplitsing
  • windowToggle - Venstercontrole met start en eind Observables
  • windowWhen - Venstersplitsing met dynamische sluitcondities

Samenvatting ​

De windowCount operator is een nuttig hulpmiddel voor het partitioneren van streams op een aantal basis en het behandelen van elke groep als een onafhankelijke Observable.

  • ✅ Ideaal voor aggregatie en verwerking op vast aantal
  • ✅ Verschillende verwerking kan worden toegepast op elk venster
  • ✅ Kan worden overlapt door startindex
  • ⚠️ Vereist abonnementbeheer
  • ⚠️ Wees bewust van geheugengebruik bij overlapping

Uitgebracht onder de CC-BY-4.0 licentie.