Una delle prime sfide che dovrai affrontare quando lavori con RxJS Observables è farli eseguire in un ordine specifico. A prima vista, questo sembra un obiettivo semplice, ma, quando si tratta di processi asincroni, nulla è mai semplice. Anche se gli osservabili vengono eseguiti in successione, non emetteranno necessariamente valori nello stesso ordine. Quindi, “ordine” può essere applicato sia all’invocazione che alla sottoscrizione.
Per complicare ulteriormente le cose, di solito vorrai passare i valori emessi all’osservabile successivo nella catena e agli abbonati. State tranquilli, RxJS fornisce l’operatore perfetto per ogni occasione; la domanda è quale utilizzare per il compito da svolgere. Si spera che il blog di oggi demistifichi alcuni compiti per la scelta dell’operatore giusto per concatenare gli osservabili.
Prima di iniziare, se hai bisogno di un aggiornamento su JavaScript Observables o ti sei perso il nostro primo articolo di questa serie, dai un’occhiata al nostro Primer RxJS Observables.
Osservabili JavaScript e concat
A volte, vogliamo che due o più osservabili si completino in successione. Per questo, c’è concatena. Tratta i tuoi oggetti osservabili come una fila alla cassa al negozio di alimentari locale; la persona successiva (abbonamento) in fila non può pagare la spesa fino a quando il cliente precedente non ha finito di pagare (completa)!
Ecco uno snippet di codice JavaScript che visualizza diversi messaggi in successione. Il concatena L’operatore assicura che i messaggi vengano visualizzati in ordine, indipendentemente dal tempo necessario per completare ogni osservabile:
// helper method const delayedMessage = (message: string, delayedTime: number) => EMPTY.pipe(startWith(message), delay(delayedTime)); const concatMessage="Concat message "; concat( delayedMessage(concatMessage + 1, 1000), delayedMessage(concatMessage + 2, 3000), delayedMessage(concatMessage + 3, 2000), delayedMessage(concatMessage + 4, 1000), delayedMessage(concatMessage + 5, 4000), // clear the screen delayedMessage('', 2000) ) .subscribe((message: any) => userMessage.innerHTML = message);
Nota che, poiché concatena attende il completamento delle osservabili prima di passare a quella successiva, se una di esse non viene completata, le osservabili successive non verranno eseguite!
Raccolta di osservabili con concatAll
In situazioni in cui si dispone di un’origine osservabile che produce altri flussi (osservabili) anziché una raccolta di flussi, è possibile utilizzare concatAll per combinarli ed emettere in sequenza tutti i valori da ogni dato flusso di input. Proprio come concatena, una volta completato il flusso attivo corrente, concatAll sottoscrive l’osservabile successivo nella sequenza. Quando vengono prodotti valori da qualsiasi sequenza combinata, tali valori vengono emessi come parte della sequenza risultante. Questo processo è spesso indicato come appiattimento.
Nel codice seguente, il di e carta geografica gli operatori sono combinati per produrre un numero di osservabili ritardati. dar loro da mangiare concatAll quindi unisce tutti i valori emessi e li trasmette agli abbonati nell’ordine in cui vengono eseguiti:
const randomDelay = (min: number, max: number) => Math.floor( Math.random() * max ) + min; const msg = 'ConcatAll message '; const observable = of(1, 2, 3, 4, 5).pipe( map((num) => of(msg + num).pipe(delay(randomDelay(1, 4) * 1000))), //merge values from inner observable concatAll() ); observable.subscribe((message: string) => userMessage.innerHTML = message);
Osservabili JavaScript e operatore di unione
Se, invece di visualizzare i messaggi nell’ordine in cui vengono eseguiti i loro osservabili, volessimo visualizzarli mentre sono completi, potremmo usare il unire operatore. È più efficiente di concatena In ciò unire crea subito tutti gli osservabili e quindi emette il loro output ai sottoscrittori non appena vengono completati. In questo senso, gli osservabili vengono ancora eseguiti nell’ordine elencato, ma il loro output viene passato una volta emesso. Ecco lo stesso frammento di codice visto in precedenza, usando unire:
// helper method const delayedMessage = (message: string, delayedTime: number) => EMPTY.pipe(startWith(message), delay(delayedTime)); const mergeMessage="Merge message "; merge( delayedMessage(mergeMessage + 1, 1000), delayedMessage(mergeMessage + 2, 3000), delayedMessage(mergeMessage + 3, 2000), delayedMessage(mergeMessage + 4, 1000), delayedMessage(mergeMessage + 5, 4000), // clear the screen delayedMessage('', 6000) ) .subscribe((message: any) => userMessage.innerHTML = message);
Ora, invece di vedere i messaggi nell’ordine di creazione di 1, 2, 3, 4, 5, appaiono in ordine di tempo di esecuzione, vale a dire 1000 (1), 1000 (4), 2000 (3), 3000 (2), 4000 (5). Un’altra ramificazione dell’uso unire è che il messaggio a schermo libero deve avere un tempo di esecuzione più lungo rispetto agli altri messaggi.
Combinazione di flussi così come vengono emessi utilizzando unisciTutti
Il unire l’operatore ha anche un equivalente unisciTutti per combinare diversi flussi osservabili interni ed emettere contemporaneamente tutti i valori del flusso di input. Piace concatAll, unisciTutti prende flussi interni (osservabili) e li emette come un nuovo flusso, che chiameremmo osservabili di ordine superiore.
Ecco il precedente concatAll esempio aggiornato per impiegare unisciTutti:
// helper method const delayedMessage = (message: string, delayedTime: number) => EMPTY.pipe(startWith(message), delay(delayedTime)); btnMergeAll.addEventListener("click", (ev: MouseEvent) => { const msg = 'MergeAll message '; const observable = of(1, 2, 3, 4, 5).pipe( map((num) => of(msg + num).pipe(delay(randomDelay(1, 4) * 1000))), //merge values from inner observable mergeAll() ); observable.subscribe((message: string) => userMessage.innerHTML = message); });
A causa del ritardo casuale, i cinque flussi precedenti possono essere emessi in qualsiasi ordine. Allo stesso modo, i flussi successivi che hanno lo stesso ritardo si sovrapporranno in modo che il primo venga immediatamente eclissato dal secondo.
Ti piace vedere i frammenti di codice sopra in azione? C’è una demo su stackblitz.com.
Concatenamento di osservabili RxJS
Questo blog ha presentato alcune opzioni per concatenare gli osservabili da eseguire in un ordine specifico. Una volta che ci hai preso la mano, puoi combinarli con operatori di trasformazione come carta geografica, mergeMap, switchMap, e mappa piatta per produrre osservabili di ordine superiore che si adattano meglio alle vostre esigenze specifiche.