Как работает оператор combLatest RxJS, когда несколько наблюдаемых выдают значения одновременно?

В Документации RxJS говорится, что

combLatest Объединяет несколько Observable для создания Observable, значения которого рассчитываются на основе последних значений каждого из его входных Observables.

Я хочу понять, как работает combLatest, когда несколько наблюдаемых выдают значения одновременно?

Если мы посмотрим на следующий код

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { timer, take, combineLatest } from 'rxjs';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: `Hello`,
})
export class App {
  name = 'Angular';

  constructor() {
    const a$ = timer(0, 1000).pipe(take(5)); //Emit values after each second (total 5 values)

    const b$ = timer(0, 4000).pipe(take(5)); //Emit values after every 4 seconds (total 5 values)

    //Marble Diagram
    
    //0 1 2 3 4
    //0       1       2       3       4

    const result$ = combineLatest(a$, b$);

    result$.subscribe((val) => console.info(val));
  }
}

bootstrapApplication(App);

Вывод выглядит следующим образом Выход В приведенном выше выводе на 4-й секунде результат $ observable выводит значения [4,0] и [4,1] одновременно.

Мой вопрос: почему он не печатает только [4,1], так как combLatest приносит последнее значение, а "4" - это последнее значение из наблюдаемого a$, а "1" - последнее значение из наблюдаемого b$ на 4-й секунде. .

Ссылка на демо

Заранее спасибо!

Чтобы расширить хороший ответ BizzyBobs: поскольку JS по своей природе является однопоточным, два события не могут произойти в одно и то же время. Во-вторых, при использовании таймеров у вас всегда есть допуск. Интервал между двумя выбросами timer(0,. 1000) никогда не равен ровно 1000 мс, а хотя бы 1000 мс.

churill 11.01.2023 07:59
Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел "Заголовок" в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
Как React Helmet спасает меня при разделении файлов CSS?
Как React Helmet спасает меня при разделении файлов CSS?
Многие новички могут столкнуться с проблемой, когда одна страница с CSS наследует свойства от другой страницы с другим CSS. У меня было много проблем,...
Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Руководство для начинающих по веб-разработке: HTML, CSS и JavaScript.
Руководство для начинающих по веб-разработке: HTML, CSS и JavaScript.
Добро пожаловать, мои коллеги по интернету, в захватывающий мир веб-разработки! Дорогие мои начинающие, я здесь, чтобы провести вас через основы HTML,...
1
1
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать его следующим образом:

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { timer, take, withLatestFrom } from 'rxjs';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: `Hello`,
})
export class App {
  name = 'Angular';

  constructor() {
    const a$ = timer(0, 1000).pipe(take(5)); //Emit values after each second (total 5 values)

    const b$ = timer(0, 4000).pipe(take(5)); //Emit values after every 4 seconds (total 5 values)

    const result$ = a$.pipe(withLatestFrom(b$, (a, b) => [a, b]));

    result$.subscribe((val) => console.info(val));
  }
}

bootstrapApplication(App);

Https://stackblitz.com/edit/angular-gsyobe?file=src/main.ts

Это обеспечивает поведение, отличное от combineLastest. combineLastest будет излучать, когда a$ или b$ излучает. Это решение излучает только тогда, когда излучает a$.

BizzyBob 10.01.2023 22:05

Это на самом деле не отвечает на вопрос. ОП спросил, почему его код ведет себя именно так. Кроме того, при размещении кода в ответе всегда полезно объяснить код, т. е. почему он лучше, как он решает конкретную проблему и т. д.

churill 11.01.2023 07:52

Я разделяю мысли БиззиБоба и Черилла. В любом случае спасибо за попытку!

mprakhar1705 11.01.2023 17:17
Ответ принят как подходящий

После того, как каждый источник выдает хотя бы одно значение, combLatest выдает каждый раз, когда выдает любой из его исходных наблюдаемых.

Даже если два наблюдаемых излучают «одновременно» (я предполагаю, что вы действительно имеете в виду в одном и том же цикле событий), combineLatest будет излучаться дважды.

Если вы хотите предотвратить выбросы, которые происходят в том же цикле событий, вы можете использовать debounceTime(0):

result$ = combineLatest(a$, b$).pipe(debounceTime(0));

Работает отлично! Спасибо за ответ по существу.

mprakhar1705 11.01.2023 17:14

Другие вопросы по теме