Подождите, пока все Observables будут завершены

У меня есть несколько Observables, подобных этому, в моем коде.

this.server.doRequest().subscribe(response => console.info(response)
      error => console.info(error),
      () => {
        console.info('completed');
      });

Может быть любое количество этих Observables, поэтому мне нужно написать функцию, которая проверяет, выполнено ли каждое Observable, в противном случае ждет завершения каждого.

Я предполагаю, что могу создать массив, вставить туда каждый новый Observable и, когда он будет завершен, удалить его по индексу. Но хорошее ли это решение?

Где я хочу его использовать. Например, у меня есть страница, на которой пользователь асинхронно загружает фотографии в любом количестве, а затем нажимает кнопку «Готово». Как только он нажал кнопку «Готово», мне нужно дождаться завершения ВСЕХ динамически созданных Observables.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
5 221
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

forkJoin(
  this.server.doRequest1(),
  this.server.doRequest2(),
  this.server.doRequest3(),
  this.server.doRequest4()
).subscribe(vals => console.info('all values', vals));

forkJoin не будет испускать до тех пор, пока не будут завершены все внутренние наблюдаемые. что делает его предпочтительным оператором для ожидания завершения нескольких наблюдаемых. Вы также можете передать ему массив наблюдаемых. Есть несколько других операторов, которые также могут подойти для вашего случая, например concat, merge, combLatest и некоторые другие.

редактировать на основе более подробной информации:

в случае использования, описанном в вашем обновлении, вы все равно захотите использовать наблюдаемый объект более высокого порядка, но forkjoin - это не то, что вам нужно. вы захотите использовать локальный объект для достижения цели, так как желание запускать каждую наблюдаемую по мере ее выбора и ожидание их выполнения все немного усложняет (но не слишком):

предположим, что у вас есть шаблон вроде:

<button (click) = "addPhoto()">Add Photo</button>

<button (click) = "finish()">Finish</button>

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

private addPhoto$ = new Subject();

constructor() {
  this.addPhoto$.pipe(
    mergeMap(() => this.uploadPhoto()),
  ).subscribe(
    (resp) => console.info('resp', resp),
    (err) => console.info('err', err),
    () => console.info('complete')
  );
}

private uploadPhoto() {
  // stub to simulate upload
  return timer(3000);
}

addPhoto() {
  this.addPhoto$.next();
}

finish() {
  this.addPhoto$.complete();
}

если вы запустите этот код, вы увидите, что добавление фотографий будет выдаваться в обработчике подписки по мере их завершения, но завершение будет срабатывать только после того, как все загрузки фотографий будут завершены и пользователь нажмет «Готово».

вот stackblitz, демонстрирующий функциональность:

https://stackblitz.com/edit/angular-bsn6pz

Будет ли выполняться doRequest2, пока doRequest1 не завершен?

tgralex 13.07.2019 16:10

Это хорошая идея. Но Observable создает динамически. Например, пользователь нажимает кнопку. Как я могу использовать динамически созданный Observerable с forkJoin

NickD 13.07.2019 16:10

@tgralex с forkJoin, все запросы выполняются параллельно. Другие операторы могут идти последовательно, если это необходимо.

bryan60 13.07.2019 16:10

@NickD довольно легко. Возможно, вам придется привести более четкий пример того, что вам нужно

bryan60 13.07.2019 16:11

Я обновил свой вопрос примером того, что я пытаюсь построить

NickD 13.07.2019 16:35

загрузка фотографий происходит, когда они выбирают фотографии или после того, как они нажимают кнопку «Готово»?

bryan60 13.07.2019 16:36

Загрузка происходит, когда пользователь выбирает фотографию

NickD 13.07.2019 16:38

Так что просто вставьте их в массив и при отправке forkJoin массив.

Roberto Zvjerković 13.07.2019 17:09

добавил другую настройку для достижения заявленной цели. forkJoin не является оператором для этого конкретного случая использования.

bryan60 13.07.2019 17:25

Это именно то, что я искал. Еще один вопрос, как я могу передать аргументы в функцию uploadPhoto?

NickD 13.07.2019 17:36

когда вы вызываете next на addPhoto $, сделайте addPhoto$.next(arg). затем это будет передано в качестве аргумента функции mergeMap, например mergeMap((arg) => this.uploadPhoto(arg))

bryan60 13.07.2019 17:39

Я бы создал словарь (в javascript, который был бы JSON с наблюдаемыми именами в качестве логических свойств), где вы нажимаете каждый наблюдаемый на «создать» и метод, который должен выполняться по завершении каждого наблюдаемого, который будет перебирать этот словарь, и если все завершено сделать что-то. Это обеспечит параллелизм и окончательное выполнение после того, как все будет завершено.

var requests = {
    doRequest1: false,
    doRequest2: false,
    doRequest3: false
};

var checkIfCAllCompleted = name => {
    requests[name] = true;
    for (var property in requests) {
        if (object.hasOwnProperty(property)) {
            if (!property) {
                return;
            }
        }
    }
    // all properties are true - do something here
    console.info("here");
}
this.server.doRequest1().then(() => checkIfCAllCompleted("doRequest1"));
this.server.doRequest2().then(() => checkIfCAllCompleted("doRequest2"));
this.server.doRequest3().then(() => checkIfCAllCompleted("doRequest3"));

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