¿Cómo puedo crear un observable con retraso?


92

Pregunta

Con fines de prueba, estoy creando Observableobjetos que reemplazan el observable que sería devuelto por una llamada http real con Http.

Mi observable se crea con el siguiente código:

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

El caso es que este observable se emite de inmediato. ¿Hay alguna forma de agregar un retraso personalizado a su emisión?


Pista

Probé esto:

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

Pero no parece funcionar.



Traté de encadenar .create(...)con .delay(1000)pero no funcionó: Observable_1.Observable.create (...). Delay no es una función.
Adrien Brunelat

1
¿Qué estás tratando de lograr exactamente?
Günter Zöchbauer

te estás suscribiendo a lo observable?
shusson

Fingir el retraso de respuesta de Http con mi propio observable. @shusson sí, la clase que estoy probando está llamando al servicio (estoy tratando de burlarme) de lo observable para suscribirme.
Adrien Brunelat

Respuestas:


144

Usando las siguientes importaciones:

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

Prueba esto:

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

ACTUALIZACIÓN: RXJS 6

La solución anterior ya no funciona en las versiones más nuevas de RXJS (y de angular, por ejemplo).

Entonces, el escenario es que tengo una variedad de elementos para verificar con una API. La API solo acepta un único elemento y no quiero eliminar la API enviando todas las solicitudes a la vez. Por lo tanto, necesito una publicación programada de elementos en la secuencia Observable con un pequeño retraso en el medio.

Utilice las siguientes importaciones:

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

Luego usa el siguiente código:

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

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

Básicamente, crea un nuevo Observable 'retrasado' para cada elemento de su matriz. Probablemente hay muchas otras formas de hacerlo, pero esto funcionó bien para mí y cumple con el "nuevo" formato RXJS.


2
La propiedad 'de' no existe en el tipo 'typeof Observable'. ¿Importas tu Observable con import {Observable} from 'rxjs/Observable';?
Adrien Brunelat

1
Desde esta página: npmjs.com/package/rxjs . Deduje que tenía que importar explícitamente con import 'rxjs/add/observable/of';. ¿Haces tú lo mismo? Sin embargo, sigue siendo extraño, ya que no se encadena con .delay (...) y muestra un error cuando intento rxjs/add/observable/delay...
Adrien Brunelat

4
debería of(item.pipe ( delay( 1000 ) ))estar of(item))).pipe(delay(1000)tratando de canalizar la matriz me dio errores
Don Thomas Boyle

1
Esto es lo que funcionó para mí con rxjs6: from ([1, 2, 3, 4, 5, 6, 7]). Pipe (concatMap (num => of (num) .pipe (delay (1000)))). suscribirse (x => console.log (x));
robert

1
La solución de @MikeOne también funcionó para mí. Es triste que se necesite tanto código para un asunto tan simple ...
Codev

103

En RxJS 5+ puedes hacerlo así

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

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

En RxJS 6+

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

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

Si desea retrasar cada valor emitido, intente

from([1, 2, 3]).pipe(concatMap(item => of(item).pipe(delay(1000))));

4
La solución más limpia en mi opinión.
Maayao

Esta "solución" solo funciona si emite un elemento. El operador de retardo no se invoca para cada elemento de un observable. Es por eso que se requiere la horrible solución concatMap.
Rick O'Shea

1
@ RickO'Shea, la pregunta es sobre un valor emitido, por eso esta solución.
Adrian Ber

1
¡Tan fresco y tan limpio!
Nahn

Actualicé mi respuesta para múltiples retrasos @ RickO'Shea
Adrian Ber

12

Lo que quieres es un temporizador:

// 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));

3
Buena respuesta, no olvides cancelar la suscripción
Sami

8

Es un poco tarde para responder ... pero por si acaso puede ser que alguien regrese a esta pregunta en busca de una respuesta

'retraso' es propiedad (función) de un Observable

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

Esto funcionó para mí ...


1
import 'rxjs/add/operator/delay' da este error ahora: Módulo no encontrado: Error: No se puede resolver 'rxjs / add / operator / delay'
Aggie Jon del 87

¿Por qué te llamarías falso observable cuando es bastante real? :)
lagoman

0

import * as Rx from 'rxjs/Rx';

Deberíamos agregar la importación anterior para que el código de soplado funcione

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

obs.subscribe(value => console.log('Subscriber: ' + value));
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.