Comment créer une observable avec un retard

92

Question

À des fins de test, je crée des Observableobjets qui remplacent l'observable qui serait retourné par un appel http réel avec Http.

Mon observable est créé avec le code suivant:

fakeObservable = Observable.create(obs => {
  obs.next([1, 2, 3]);
  obs.complete();
});

Le fait est que cette observable émet immédiatement. Existe-t-il un moyen d'ajouter un délai personnalisé à son émission?


Piste

J'ai essayé ceci:

fakeObservable = Observable.create(obs => {
  setTimeout(() => {
    obs.next([1, 2, 3]);
    obs.complete();
  }, 100);
});

Mais cela ne semble pas fonctionner.

Adrien Brunelat
la source
J'ai essayé d'enchaîner .create(...)avec .delay(1000)mais cela n'a pas fonctionné: Observable_1.Observable.create (...). Delay is not a function.
Adrien Brunelat
1
Qu'essayez-vous d'accomplir exactement?
Günter Zöchbauer
vous abonnez-vous à l'observable?
shusson
Faux le délai de réponse Http avec mon propre observable. @shusson ouais, la classe que je teste appelle le service (j'essaye de me moquer) pour l'observable afin de s'y abonner.
Adrien Brunelat

Réponses:

144

À l'aide des importations suivantes:

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/delay';

Essaye ça:

let fakeResponse = [1,2,3];
let delayedObservable = Observable.of(fakeResponse).delay(5000);
delayedObservable.subscribe(data => console.log(data));

MISE À JOUR: RXJS 6

La solution ci-dessus ne fonctionne plus vraiment dans les nouvelles versions de RXJS (et d'angular par exemple).

Donc, le scénario est que j'ai un tableau d'éléments à vérifier avec une API. L'API n'accepte qu'un seul élément et je ne souhaite pas tuer l'API en envoyant toutes les demandes en même temps. J'ai donc besoin d'une publication chronométrée des éléments sur le flux Observable avec un petit délai entre les deux.

Utilisez les importations suivantes:

import { from, of } from 'rxjs';
import { delay } from 'rxjs/internal/operators';
import { concatMap } from 'rxjs/internal/operators';

Ensuite, utilisez le code suivant:

const myArray = [1,2,3,4];

from(myArray).pipe(
        concatMap( item => of(item).pipe ( delay( 1000 ) ))
    ).subscribe ( timedItem => {
        console.log(timedItem)
    });

Il crée essentiellement un nouvel observable «retardé» pour chaque élément de votre tableau. Il existe probablement de nombreuses autres façons de le faire, mais cela a bien fonctionné pour moi et est conforme au «nouveau» format RXJS.

MikeOne
la source
2
La propriété 'of' n'existe pas sur le type 'typeof Observable'. Importez-vous votre Observable avec import {Observable} from 'rxjs/Observable';?
Adrien Brunelat
1
Depuis cette page: npmjs.com/package/rxjs . J'ai déduit que je devais importer explicitement avec import 'rxjs/add/observable/of';. Faites-vous la même chose? C'est quand même étrange, car il ne s'enchaîne pas avec .delay (...) et il affiche une erreur lorsque j'essaye rxjs/add/observable/delay...
Adrien Brunelat
4
devrait of(item.pipe ( delay( 1000 ) ))être of(item))).pipe(delay(1000)essayer de tuyau le tableau m'a donné des erreurs
Don Thomas Boyle
1
C'est ce qui a fonctionné pour moi avec rxjs6: from ([1, 2, 3, 4, 5, 6, 7]). Pipe (concatMap (num => of (num) .pipe (delay (1000)))). s'abonner (x => console.log (x));
robert le
1
La solution de @MikeOne a fonctionné pour moi aussi. Triste que tant de code soit nécessaire pour une question aussi simple ...
Codev
103

Dans RxJS 5+, vous pouvez le faire comme ça

import { Observable } from "rxjs/Observable";
import { of } from "rxjs/observable/of";
import { delay } from "rxjs/operators";

fakeObservable = of('dummy').pipe(delay(5000));

Dans RxJS 6+

import { of } from "rxjs";
import { delay } from "rxjs/operators";

fakeObservable = of('dummy').pipe(delay(5000));

Si vous voulez retarder chaque valeur émise, essayez

from([1, 2, 3]).pipe(concatMap(item => of(item).pipe(delay(1000))));
Adrian Ber
la source
4
La solution la plus propre à mon avis.
Maayao le
Cette "solution" ne fonctionne que si vous émettez un élément. L'opérateur de retard n'est pas appelé pour chaque élément d'une observable. C'est pourquoi la solution horrible concatMap est nécessaire.
Rick O'Shea
1
@ RickO'Shea, la question porte sur une valeur émise, c'est pourquoi cette solution.
Adrian Ber
1
Si frais et si propre!
Nahn le
J'ai mis à jour ma réponse pour plusieurs retards @ RickO'Shea
Adrian Ber
12

Ce que vous voulez, c'est une minuterie:

// RxJS v6+
import { timer } from 'rxjs';

//emit [1, 2, 3] after 1 second.
const source = timer(1000).map(([1, 2, 3]);
//output: [1, 2, 3]
const subscribe = source.subscribe(val => console.log(val));
Pastille
la source
3
Bonne réponse, n'oubliez pas de vous désinscrire
Sami
8

Il est peu tard pour répondre ... mais juste au cas où quelqu'un reviendrait à cette question à la recherche d'une réponse

'delay' est la propriété (fonction) d'un observable

fakeObservable = Observable.create(obs => {
  obs.next([1, 2, 3]);
  obs.complete();
}).delay(3000);

Cela a fonctionné pour moi ...

microchip78
la source
1
import 'rxjs/add/operator/delay' donne cette erreur maintenant: Module non trouvé: Erreur: Impossible de résoudre 'rxjs / add / operator / delay'
Aggie Jon du 87
Pourquoi vous qualifieriez-vous de faux observable alors que c'est bien réel? :)
lagoman
0

import * as Rx from 'rxjs/Rx';

Nous devrions ajouter l'importation ci-dessus pour que le code de coup fonctionne

Let obs = Rx.Observable
    .interval(1000).take(3);

obs.subscribe(value => console.log('Subscriber: ' + value));
Narendra Kumar Achari
la source