Quelle serait la façon la plus idiomatique de produire des valeurs d'un observable dans un laps de temps spécifique? Par exemple, disons que j'ai un observable créé à partir d'un grand tableau et que je veux donner une valeur toutes les 2 secondes. Une combinaison de interval
et selectMany
est-elle la meilleure façon?
Pour votre exemple spécifique, l'idée est de mapper chaque valeur du tableau à un observable qui donnera son résultat après un délai, puis de concaténer le flux résultant d'observables:
var delayedStream = Rx.Observable
.fromArray([1, 2, 3, 4, 5])
.map(function (value) { return Rx.Observable.return(value).delay(2000); })
.concatAll();
D'autres exemples pourraient en effet utiliser timer
ou interval
. Ça dépend.
Par exemple, si votre tableau est vraiment très volumineux, alors ce qui précède entraînera une quantité importante de pression sur la mémoire (car il crée N
observables pour un très grand N
). Voici une alternative qui utilise interval
pour parcourir le tableau paresseusement:
var delayedStream = Rx.Observable
.interval(2000)
.take(reallyBigArray.length) // end the observable after it pulses N times
.map(function (i) { return reallyBigArray[i]; });
Celui-ci donnera la valeur suivante du tableau toutes les 2 secondes jusqu'à ce qu'il ait itéré sur tout le tableau.
Je pense que l'utilisation de Zip produit un code meilleur et plus lisible, en utilisant toujours seulement 3 observables.
var items = ['A', 'B', 'C'];
Rx.Observable.Zip(
Rx.Observable.fromArray(items),
Rx.Observable.timer(2000, 2000),
function(item, i) { return item;}
)
Alors que la réponse de Brandon obtient l'essentiel de l'idée, voici une version qui donne immédiatement le premier élément, puis met du temps entre les éléments suivants.
var delay = Rx.Observable.empty().delay(2000);
var items = Rx.Observable.fromArray([1,2,3,4,5])
.map(function (x) {
return Rx.Observable.return(x).concat(delay); // put some time after the item
})
.concatAll();
Mis à jour pour les nouveaux RxJS:
var delay = Rx.Observable.empty().delay(2000);
var items = Rx.Observable.fromArray([1,2,3,4,5])
.concatMap(function (x) {
return Rx.Observable.of(x).concat(delay); // put some time after the item
});
Pour RxJS 5:
Rx.Observable.from([1, 2, 3, 4, 5])
.Zip(Rx.Observable.timer(0, 2000), x => x)
.subscribe(x => console.log(x));
Convenez que Zip est une approche propre. Voici une fonction réutilisable pour générer un flux d'intervalle pour un tableau:
function yieldByInterval(items, time) {
return Rx.Observable.from(items).Zip(
Rx.Observable.interval(time),
function(item, index) { return item; }
);
}
// test
yieldByInterval(['A', 'B', 'C'], 2000)
.subscribe(console.log.bind(console));
Cela s'appuie sur réponse de farincz , mais est légèrement plus court en utilisant .Zip
Comme méthode d'instance.
En outre, j'ai utilisé Rx.Observable.from()
parce que Rx.Observable.fromArray()
est obsolète .
Pour RxJS v6, obtenir le suivant avec un retard de 2 secondes.
Exemple 1. concatMap:
import {of} from 'rxjs';
import {concatMap, delay} from 'rxjs/operators';
of(1, 2, 3, 4, 5)
.pipe(
concatMap(x => of(x)
.pipe(
delay(2000))
)
)
.subscribe({
next(value) {
console.log(value);
}
});
Exemple 2. map + concatAll:
import {of} from 'rxjs';
import {concatAll, delay, map} from 'rxjs/operators';
of(1, 2, 3, 4, 5)
.pipe(
map(x => of(x)
.pipe(
delay(2000))
),
concatAll()
)
.subscribe({
next(value) {
console.log(value);
}
});
En s'appuyant sur les solutions Zip de farincz et user3587412, voici comment cela fonctionne dans RxJS v6
const { Zip, from, timer } = require("rxjs")
const { map } = require("rxjs/operators")
const input = [1, 2, 3, 4, 5]
const delay = 2000
Zip(
from(input),
timer(0, delay)
).pipe(
map(([ delayedInput, _timer ]) => delayedInput) // throw away timer index
).subscribe(
console.log
)