Como posso criar um observável com atraso


94

Questão

Para fins de teste, estou criando Observableobjetos que substituem o observável que seria retornado por uma chamada real de http com Http.

Meu observável é criado com o seguinte código:

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

A questão é que este observável emite imediatamente. Existe uma maneira de adicionar um atraso personalizado à sua emissão?


Track

Eu tentei isso:

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

Mas não parece funcionar.



Tentei encadear .create(...)com, .delay(1000)mas não funcionou: Observable_1.Observable.create (...). Delay is not a function.
Adrien Brunelat

1
O que exatamente você está tentando realizar?
Günter Zöchbauer

você está assinando o observável?
shusson

Falsifique o atraso de resposta Http com meu próprio observável. @shusson sim, a classe que estou testando está chamando o serviço (estou tentando simular) para o observável para assiná-lo.
Adrien Brunelat

Respostas:


150

Usando as seguintes importações:

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

Experimente isto:

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

ATUALIZAÇÃO: RXJS 6

A solução acima realmente não funciona mais nas versões mais recentes do RXJS (e do angular, por exemplo).

Portanto, o cenário é que tenho uma série de itens para verificar com uma API. A API aceita apenas um único item e não quero encerrar a API enviando todas as solicitações de uma vez. Portanto, preciso de uma liberação cronometrada de itens no fluxo Observável com um pequeno atraso no meio.

Use as seguintes importações:

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

Em seguida, use o seguinte código:

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

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

Basicamente, ele cria um novo Observable 'atrasado' para cada item em sua matriz. Provavelmente existem muitas outras maneiras de fazer isso, mas funcionou bem para mim e está em conformidade com o 'novo' formato RXJS.


2
A propriedade 'of' não existe no tipo 'typeof Observable'. Você importa seu Observável com import {Observable} from 'rxjs/Observable';?
Adrien Brunelat

1
Nesta página: npmjs.com/package/rxjs . Deduzi que precisava importar explicitamente com import 'rxjs/add/observable/of';. Você faz a mesma coisa? Ainda é estranho, pois não irá encadear com .delay (...) e mostra um erro quando tento rxjs/add/observable/delay...
Adrien Brunelat

4
deveria of(item.pipe ( delay( 1000 ) ))estar of(item))).pipe(delay(1000)tentando canalizar o array me deu erros
Don Thomas Boyle

1
Isso é o que funcionou para mim com rxjs6: from ([1, 2, 3, 4, 5, 6, 7]). Pipe (concatMap (num => of (num) .pipe (delay (1000)))). assinar (x => console.log (x));
robert de

1
A solução da @MikeOne funcionou para mim também. Triste que tanto código seja necessário para um assunto tão simples ...
Codev

104

No RxJS 5+, você pode fazer assim

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

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

Em RxJS 6+

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

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

Se você quiser atrasar cada valor emitido, tente

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

4
A solução mais limpa na minha opinião.
Maayao

Esta "solução" só funciona se você emitir um item. O operador de atraso não é chamado para cada elemento em um observável. É por isso que a horrível solução concatMap é necessária.
Rick O'Shea

1
@RickO'Shea, a questão é sobre um valor emitido, por isso esta solução.
Adrian Ber

1
Tão fresco e tão limpo !
Nahn,

Atualizei minha resposta para vários atrasos @ RickO'Shea
Adrian Ber

12

O que você quer é um cronômetro:

// 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
Boa resposta, não se esqueça de cancelar a inscrição
Sami

8

É um pouco tarde para responder ... mas no caso de alguém voltar a esta questão procurando uma resposta

'atraso' é propriedade (função) de um observável

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

Isso funcionou para mim ...


1
import 'rxjs/add/operator/delay' dá este erro agora: Módulo não encontrado: Erro: Não é possível resolver 'rxjs / add / operator / delay'
Aggie Jon de 87

Por que você o chamaria de falso observável quando é bem real? :)
lagoman

0

import * as Rx from 'rxjs/Rx';

Devemos adicionar a importação acima para fazer o código de sopro funcionar

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

obs.subscribe(value => console.log('Subscriber: ' + value));
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.