Непонятное поведение оператора rxjs `delay` - PullRequest
3 голосов
/ 08 июля 2019

Я немного запутался в операторе rxjs delay.

Когда я тестирую его с поддельной наблюдаемой, созданной с помощью from, тогда я вижу только начальную задержку:

const { from } = Rx;
const { delay, tap } = RxOperators;

from([1, 2, 3, 4]).pipe(
  tap(console.log),
  delay(1000));

(Вы можете скопировать и вставить этот фрагмент кода в rxviz .)

Я поместил туда tap, чтобы убедиться, что from фактически выдает элементы массива как отдельные значения вместо одного значения массива.

Первоначальная задержка - не то, что я ожидал, но, по крайней мере, это то, что документы говорят:

[...] это время оператора смещает источник, наблюдаемый на это количество времени, выраженное в миллисекундах. Относительные временные интервалы между значениями сохраняются.

Однако, когда я тестирую его с помощью наблюдаемой, созданной из события, тогда я вижу задержку перед каждым излучаемым значением :

const { fromEvent } = Rx;
const { delay } = RxOperators;

fromEvent(document, 'click')
  .pipe(delay(1000))

Что здесь происходит? Почему delay ведет себя по-разному в обоих случаях?

Ответы [ 3 ]

2 голосов
/ 09 июля 2019

Все delay делает то, что говорит: всякий раз, когда он получает значение, он удерживает это значение в течение периода задержки, а затем выдает его. Он делает то же самое для каждого значения, которое он получает. delay не не меняет относительное время между элементами в потоке.

Итак, когда вы делаете from([1,2,3,4]).pipe(delay(1000)), происходит следующее:

  • Время 0: from испускает 1
  • Время 0: delay видит 1 и запускает таймер1
  • Время 0: from испускает 2
  • Время 0: delay видит 2 и запускает таймер2
  • ...
  • Время 1000: таймер1 завершается и delay испускает 1
  • Время 1000: таймер2 завершается и delay испускает 2
  • ...

Таким образом, поскольку все 4 значения были переданы в быстрой последовательности, вы действительно видите только начальную задержку, а затем все 4 значения передаются в нисходящем направлении. В действительности каждое значение было задержано на 1 секунду с момента его первоначального выброса.

Если вы хотите «разложить» элементы так, чтобы они были на расстоянии не менее 1 секунды, то вы можете сделать что-то вроде:

const source = from([1, 2, 3, 4])
const spread = source.pipe(concatMap(value => of(value).pipe(delay(1000))));
spread.subscribe(value => console.log(value));

Это преобразует каждое отдельное значение в наблюдаемое, которое выдает значение после задержки, а затем объединяет эти наблюдаемые. Это означает, что таймер для каждого элемента не будет тикать, пока не закончится таймер предыдущего элемента.

1 голос
/ 09 июля 2019

Вы нажимаете на поток и получаете значения, которые испускаются, затем вы отправляете их в задержку, которая генерирует их через одну секунду. Каждая функция в конвейере возвращает новую наблюдаемую величину, которая выдает значение следующей функции в конвейере. Tap возвращает ту же наблюдаемую, которая еще не была отложена, а delay возвращает наблюдаемую, которая излучает одну секунду спустя.

const { from } = rxjs;
const { delay, tap } = rxjs.operators;

from([1, 2, 3, 4]).pipe(
  tap(val => { console.log(`Tap: ${val}`); }),
  delay(1000)).subscribe(val => { console.log(`Sub: ${val}`); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.2/rxjs.umd.min.js"></script>

Если вы поставите кран после задержки, вы увидите их после задержки.

const { from } = rxjs;
const { delay, tap } = rxjs.operators;

from([1, 2, 3, 4]).pipe(
  delay(1000),
  tap(val => { console.log(`Tap: ${val}`); })).subscribe(val => { console.log(`Sub: ${val}`); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.2/rxjs.umd.min.js"></script>
1 голос
/ 08 июля 2019

В первом фрагменте кода вы отправляете элемент массива за элементом. Сначала обрабатывается задержка, затем элементы массива.

'from' и 'pipe' заставляют 'delay' выполнить один раз. Обработка последовательности труб, сначала задержка, затем нажмите, нажмите, нажмите, нажмите.

Во втором фрагменте кода вы излучаете объекты (они прибывают), поэтому задержка происходит один раз для каждого объекта.

'fromEvent' и 'pipe' делают 'delay' для каждого события. Обработка последовательности конвейеров задержки перед каждым событием.

...