При работе с наблюдаемыми, вы не будете часто звонить по подписке. Вместо этого вы будете использовать различные операторы, чтобы объединить наблюдаемые вместе, образуя конвейер операций.
Чтобы взять выходные данные одной наблюдаемой и превратить ее в другую, основной оператор - map
. Это похоже на то, как вы можете .map
массив создать другой массив. Для простого примера вот удвоение всех значений наблюдаемой:
const myObservable = of(1, 2, 3).pipe(
map(val => val * 2)
);
// myObservable is an observable which will emit 2, 4, 6
Сопоставление - это также то, что вы делаете, чтобы взять наблюдаемый для одного http-запроса, а затем сделать еще один http-запрос. Однако нам понадобится еще одна часть, поэтому следующий код не совсем верен:
const myObservable = http.get('someUrl').pipe(
map(result => http.get('someOtherUrl?id=' + result.id)
)
Проблема с этим кодом в том, что он создает наблюдаемую область, которая выплевывает другие наблюдаемые. 2-мерная наблюдаемая, если хотите. Нам нужно сгладить это так, чтобы у нас была наблюдаемая, которая выплевывает результаты второго http.get. Есть несколько различных способов сделать сглаживание, в зависимости от того, в каком порядке мы хотим, чтобы результаты были в том случае, если несколько наблюдаемых излучают несколько значений. Это не большая проблема в вашем случае, так как каждая из этих наблюдаемых http будет излучать только один элемент. Но для справки, вот варианты:
- mergeMap позволит всем наблюдаемым работать в любом порядке и выводить в любом порядке поступающие значения. Это имеет свое применение, но также может привести к условиям гонки
- switchMap переключится на последние наблюдаемые и отменит старые, которые могут быть в процессе. Это может устранить условия гонки и обеспечить наличие только самых последних данных.
- concatMap завершит всю первую наблюдаемую, прежде чем перейти ко второй. Это также может устранить условия гонки, но не отменит старую работу.
Как я уже сказал, это не имеет большого значения в вашем случае, но я бы порекомендовал использовать switchMap. Так что мой маленький пример выше стал бы:
const myObservable = http.get('someUrl').pipe(
switchMap(result => http.get('someOtherUrl?id=' + result.id)
)
Теперь вот как я могу использовать эти инструменты с вашим кодом. В этом примере кода я не сохраняю все данные this.result, this.dependentKey и т. Д .:
getDataFromRemoteServer() {
return this.http.get(`/api/point/id`).pipe(
map(result => someComplexSyncTransformation(result)),
switchMap(dependentKey => this.http.get(`/api/point/id/dependent/keys/${dependentKey}`)),
switchMap(dependantResult => this.http.get(`/api/point/id/dependent/keys/${dependentResult.someValue}`)
});
}
// to be used like:
getDataFromRemoteServer()
.subscribe(deeplyNestedResult => {
// do whatever with deeplyNestedResult
});
Если для вас важно сохранить эти значения, то я бы рекомендовал использовать оператор касания, чтобы выделить тот факт, что вы генерируете побочные эффекты. tap будет запускать некоторый код всякий раз, когда наблюдаемое выдает значение, но не будет связываться со значением:
getDataFromRemoteServer() {
return this.http.get(`/api/point/id`).pipe(
tap(result => this.result = result),
map(result => someComplexSyncTransformation(result)),
tap(dependentKey => this.dependentKey = dependentKey),
// ... etc
});
}