У меня есть несколько Observables, подобных этому, в моем коде.
this.server.doRequest().subscribe(response => console.info(response)
error => console.info(error),
() => {
console.info('completed');
});
Может быть любое количество этих Observables, поэтому мне нужно написать функцию, которая проверяет, выполнено ли каждое Observable, в противном случае ждет завершения каждого.
Я предполагаю, что могу создать массив, вставить туда каждый новый Observable и, когда он будет завершен, удалить его по индексу. Но хорошее ли это решение?
Где я хочу его использовать. Например, у меня есть страница, на которой пользователь асинхронно загружает фотографии в любом количестве, а затем нажимает кнопку «Готово». Как только он нажал кнопку «Готово», мне нужно дождаться завершения ВСЕХ динамически созданных Observables.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


для этого вам следует использовать наблюдаемые объекты более высокого порядка, ваш конкретный вариант использования будет диктовать точный оператор, но 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
Это хорошая идея. Но Observable создает динамически. Например, пользователь нажимает кнопку. Как я могу использовать динамически созданный Observerable с forkJoin
@tgralex с forkJoin, все запросы выполняются параллельно. Другие операторы могут идти последовательно, если это необходимо.
@NickD довольно легко. Возможно, вам придется привести более четкий пример того, что вам нужно
Я обновил свой вопрос примером того, что я пытаюсь построить
загрузка фотографий происходит, когда они выбирают фотографии или после того, как они нажимают кнопку «Готово»?
Загрузка происходит, когда пользователь выбирает фотографию
Так что просто вставьте их в массив и при отправке forkJoin массив.
добавил другую настройку для достижения заявленной цели. forkJoin не является оператором для этого конкретного случая использования.
Это именно то, что я искал. Еще один вопрос, как я могу передать аргументы в функцию uploadPhoto?
когда вы вызываете next на addPhoto $, сделайте addPhoto$.next(arg). затем это будет передано в качестве аргумента функции mergeMap, например mergeMap((arg) => this.uploadPhoto(arg))
Я бы создал словарь (в 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"));
Будет ли выполняться doRequest2, пока doRequest1 не завершен?