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.

Adrien Brunelat
fonte
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.

MikeOne
fonte
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))));
Adrian Ber
fonte
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));
Pelota
fonte
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 ...

microchip78
fonte
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));
Narendra Kumar Achari
fonte