У меня есть 2 подписки в проекте angular/typescript.
Эти 2 подписки подписываются на каждый из своих наблюдаемых A
и B
, которые находятся вне компонента и в сервисном файле.
Иногда A
меняется, а B
может не изменяться в зависимости от действия какого-либо компонента и наоборот.
Однако обычно B
изменяется после A
изменений в другом компоненте.
Кроме того, B
должен что-то сделать после проверки правильного значения A
. Поэтому все, о чем я могу думать, это вложенная подписка с оператором if, как показано ниже.
ngOnInit(){
this.A = this.serviceX.a.subscribe(
data =>{
this.temp = data;
if (data=='correct'){
this.B = this.serviceX.b.subscribe(
beta => {
console.info('Sure'+this.temp);
}
)
}
}
)
}
Пока работает? Но я видел другой пост, в котором говорилось, что это не очень хороший подход. Итак, я попробовал combineLatest
и forkJoin
. Но похоже, они работают только в том случае, если оба наблюдаемых изменения. И не будет вызываться, если один из наблюдаемых вообще не изменится. Поправьте меня если я ошибаюсь.
Так что теперь все, о чем я могу думать, это отдельная подписка и подписка на них одну за другой, как показано ниже.
this.A = this.serviceX.a.subscribe(
data =>{
this.temp = data ;
}
)
this.B = this.serviceX.b.subscribe(
beta =>{
if (this.temp=='correct'){
console.info('Sure'+this.temp)
}
}
)
Но я очень обеспокоен тем, что делаю это неправильно и делаю нестабильную итерацию. Что такое оператор rxjs, который я могу использовать, чтобы убедиться, что подписка B подписывается только после того, как подписка A будет изменена (однако A, возможно, не будет изменена некоторое время)? И в конечном итоге сделать всю процедуру более надежной?
this.A
и this.B
объявлены только для того, чтобы я мог unsubscribe()
их позже.
А как насчет this.temp
? Он используется только для проверки на B? Где и как вы на самом деле используете значения, полученные из A и B?
Да this.temp
используется только для проверки B
. Я использую значение, полученное из A
и B
, для изменения другой переменной в том же классе. Проблема в том, что B
нужно дождаться окончания A
, если бы A
были какие-либо изменения для правильного ответа. Однако в некоторых случаях A
может вообще не измениться, а изменится только B
.
Ваш комментарий выше показывает очень запутанную логику, которая не ясна в вашем исходном вопросе. Поэтому вам будет сложно получить хороший конкретный ответ, как вы можете видеть по разбросу существующих ответов плюс мой теперь удаленный ответ.
Возможно, вы ищете flatMap
, вы можете сопоставить несколько подписок, каждая flatMap
должна возвращать свою собственную Observable
и подписываться только в конце.
this.serviceX.a.pipe(flatMap(data => {
this.temp = data;
if (data == 'correct') {
return this.serviceX.b.pipe(
flatMap(beta => {
this.temp2 = beta;
console.info('Sure' + this.temp);
return this.serviceX.c.pipe(map(delta => {
this.temp3 = delta;
console.info('Sure' + this.temp2);
return delta;
}));
}));
}
})).subscribe(delta => {
console.info('Complete all subscriptions');
});
Подписка внутри обработчика подписки может привести к путанице, и я считаю, что ее можно и нужно всегда избегать. Ваш основной рабочий процесс - как я понял ваш код - таков:
serviceX.a
serviceX.b
Теперь вы можете найти подходящий оператор для каждого шага. Вот как бы я это сделал:
this.serviceX.a.pipe( // 1 - load from a
tap(data => this.temp = data), // 2 - side effect
filter(data => data == 'correct'), // 3a - if
concatMap(() => this.serviceX.b) // 3b - load from b
).subscribe((beta) =>
console.info('Sure' + this.temp) // 4 - actual subscribe
);
Примечание 1. Здесь вам нужна только одна подписка.
Примечание 2. В зависимости от вашего варианта использования вы можете заменить concatMap на switchMap , ExhaustMap или mergeMap.
Примечание 3: использование temp
здесь довольно опасно. В зависимости от того, какой *map
-оператор вы выберете, вы можете создать состояние гонки. Пока вы ждете выброса serviceX.b
serviceX.a
уже может выдать следующее значение и перезаписать temp
. Если единственная причина для temp
— сохранить результат из serviceX.a
, вместо этого вам следует использовать это решение:
Есть ли оператор, позволяющий сохранить начальное значение подписки после выполнения ,,switchMap"?
Просто хочу подтвердить, иногда A
может не быть изменений и, следовательно, никакой next()
операции, испускающей все такое, вы уверены, что B
все еще будет работать, если только B
что-то изменить?
@AkiZukiLenn Нет, не будет. Извините, это не было ясно из вашего вопроса. Вы сказали: «Иногда A изменяется, а B может быть не [...]», но вы также сказали: «Кроме того, B должен что-то сделать после проверки правильного значения A» (я интерпретирую B работает после A). Теперь мне не совсем понятно, что должно происходить в каком порядке. Оба могут измениться, но B должен проверить значение A. Так что же должно произойти, если A не излучает? Что должен проверить Б? И как вы проверяете, не излучает ли A, или, может быть, он просто излучает после B из-за неудачи?
@AkiZukiLenn tldr; Я был бы рад предложить решение, но вижу, что не до конца понял ваш вопрос. Нам может понадобиться больше деталей, и вы должны разработать план, когда что должно произойти :)
1. A
излучает, B
«может» не излучает, и на этом операция заканчивается. 2. Теперь, если после того, как A
излучает, B
также излучает, то B
должен дождаться, пока A
закончит излучение, чтобы A
вернул окончательный ответ. 3. Кроме того, после того, как A
излучает, а B
излучает, B
может снова излучаться, а A
ничего не излучает. Таким образом, есть то, что «иногда может случиться иногда не путать». Это делает мой вопрос более ясным?
Я бы сказал, что B
должен испускаться после A
, поскольку логически пользователь может получить доступ только к A
до B
. По крайней мере, с точки зрения маршрутизации. Итак, как только пользователь нажимает ссылку A
, A регистрируется и излучает. Затем, основываясь на значении, испускаемом A
, B
также может излучать. Хотя B
может излучать много раз, но A
ничего не излучает, так как A
уже излучается. Таким образом, я не могу понять, как я могу использовать оператор filter rxjs.
@AkiZukiLenn Честно говоря, это кажется довольно запутанным дизайном. Мой ответ должен работать, если ваш второй комментарий верен и B
может излучаться только после A
. Иногда полезно использовать ReplaySubject
или BehaviorSubject
для обработки просроченных подписок, надеюсь, у вас это получится ;)
Да, дело в том, что он отлично работает, если я делаю их обоими BehaviorSubject, он работает нормально. Мне просто интересно, есть ли оператор лучше.
Вызов subscribe
внутри другой подписки является плохой практикой, потому что вы сломали поток и начали с другого потока (в вашем примере подписчик внутри никогда не уничтожается, это может вызвать проблемы с памятью, вы создаете нового подписчика B каждый раз, когда поток входит в A , а это.Б.Отписаться уничтожить только последнее).
Затем вам нужно продолжать управлять своим Стримом оператором mergeMap
или switchMap
и вызывать только один Subscribe в конце.
Для фильтрации потока вы можете использовать оператор filter
.
this.serviceX.a.pipe(
filter((data: any) => data == 'correct'),
switchMap((value: any) => this.serviceX.b)
)
.subscribe((value: any) =>
console.info('Sure' + this.temp);
);
После этого у вас останется только 1 подписчик, от которого нужно отписаться.
Как/где вы используете
this.A
иthis. B
?