Як я можу створити спостережуваний із затримкою


93

Питання

Для цілей тестування я створюю Observableоб'єкти, які замінюють спостережуваний, який повертається фактичним викликом http Http.

Моє спостережуване створюється з таким кодом:

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

Справа в тому, що це спостережуване виділяє негайно. Чи є спосіб додати спеціальну затримку до її викиду?


Трек

Я спробував це:

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

Але це, здається, не працює.



Я намагався ланцюга .create(...)з , .delay(1000)але це не робота :. Observable_1.Observable.create (...) затримка не є функцією.
Адріен Брунелат,

1
Що саме ви намагаєтесь досягти?
Günter Zöchbauer

ви підписані на спостережуване?
shusson

Підробляйте затримку відповіді Http моїм власним спостережуваним. @shusson так, клас, який я тестую, викликає службу (я намагаюся знущатися) для спостережуваного, щоб підписатися на нього.
Адріен Брунелат,

Відповіді:


145

Використовуючи такі імпорти:

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

Спробуйте це:

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

ОНОВЛЕННЯ: RXJS 6

Наведене вище рішення насправді вже не працює в нових версіях RXJS (і, наприклад, angular).

Отже, сценарій полягає в тому, що у мене є масив елементів для перевірки за допомогою API. API приймає лише один елемент, і я не хочу вбивати API, надсилаючи всі запити одночасно. Тож мені потрібен часовий випуск елементів у потоці Observable з невеликою затримкою між ними.

Використовуйте такі імпорти:

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

Потім використовуйте такий код:

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

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

Це в основному створює нове сповільнене спостереження для кожного елемента у вашому масиві. Можливо, існує багато інших способів зробити це, але це для мене добре працювало і відповідає "новому" формату RXJS.


2
Властивість 'of' не існує для типу 'typeof Observable'. Ви імпортуєте ваш Observable з import {Observable} from 'rxjs/Observable';?
Адріен Брунелат,

1
З цієї сторінки: npmjs.com/package/rxjs . Я вивів мені довелося явно імпортувати з import 'rxjs/add/observable/of';. Ви випадково робите те саме? Хоча все одно це дивно, оскільки він не буде пов’язаний із .delay (...) і відображає помилку, коли я намагаюся rxjs/add/observable/delay...
Адріен Брунелат

4
має of(item.pipe ( delay( 1000 ) ))бути of(item))).pipe(delay(1000)намагаємося труба масив дав мені помилки
Дон Томас Бойл

1
Це те, що працювало у мене з rxjs6: from ([1, 2, 3, 4, 5, 6, 7]). Pipe (concatMap (num => of (num) .pipe (delay (1000)))). передплатити (x => console.log (x));
Роберт

1
Рішення @MikeOne спрацювало і на мене. Сумно, що для такої простої справи потрібно стільки коду ...
Кодев

103

У RxJS 5+ ви можете зробити це так

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

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

У RxJS 6+

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

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

Якщо ви хочете затримати кожне випущене значення, спробуйте

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

4
Найчистіше рішення, на мій погляд.
Maayao

Це "рішення" працює лише в тому випадку, якщо ви випускаєте один елемент. Оператор затримки не викликається для кожного елемента в спостережуваному. Ось чому потрібне жахливе рішення concatMap.
Рік О'Ші

1
@ RickO'Shea, питання полягає в одному випущеному значенні, тому саме це рішення.
Адріан Бер

1
Такий свіжий і такий чистий!
Нан,

Я оновив свою відповідь щодо багаторазових затримок @ RickO'Shea
Адріан Бер

12

Те, що вам потрібно, - це таймер:

// 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
Гарна відповідь, не забудьте скасувати підписку
Самі

8

Відповісти пізно ... але про всяк випадок може хтось повернутися до цього питання, шукаючи відповіді

"затримка" є властивістю (функцією) спостережуваного

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

Це спрацювало для мене ...


1
import 'rxjs/add/operator/delay' видає цю помилку зараз: Модуль не знайдено: Помилка: Не вдається вирішити 'rxjs / add / operator / delay'
Еггі Джон від 87

Чому ви називаєте себе підробною підробкою, коли це цілком реально? :)
lagoman

0

import * as Rx from 'rxjs/Rx';

Ми повинні додати вищевказаний імпорт, щоб змусити код удару працювати

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

obs.subscribe(value => console.log('Subscriber: ' + value));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.