加入可以在一个可观察对象中有条件地发生的多个 http 调用
Join multiple http calls that can happen conditionally in one observable
为了示例起见,假设我有一个名为客户端的实体:
interface Client {
id: number
name: string
address: Address[]
}
interface Address {
id: number
street: string
}
在这种情况下,我无法在同一调用中更新客户端的 name
和他的 addresses
。
相反,我需要:
- 勾选要创建的地址,然后一个一个创建(并存储后面要用到的值)
- 勾选要更新的地址,然后一一更新(并存储后面要用到的值)
- 最后再打电话给客户的名字。
所以我想做的是加入可以在一个可观察对象中有条件地发生的多个 http 调用。
这是我目前拥有的:
updateClientAndClientAddresses(): Observable<Client> {
return of({}).pipe(
******* Conditionally make all the create addresses calls *******
******* Conditionally make all the update addresses calls *******
******* Then make the update name call *******
switchMap(([updateNameResponse: Client, responseOfAllAddressesToBeCreated: Address, responseOfAllAddressesToUpdated: Address]) => {
// Ideally here I will have the results of all the calls made so far.
// Merge everything manually here
return {
...updateClientCallResponse,
addresses: [
...responseOfAllAddressesToBeCreated,
...responseOfAllAddressesToUpdated
]};
}),
)
}
只是为了加强:
在调用更新名称之前,我需要检查是否:
addressesToBeCreated.length
如果是,我需要对该数组的每个长度执行一个特定的调用,等待响应并存储结果以供稍后使用。
然后我需要检查是否:
addressesToUpdated.length
如果是,我需要对该数组的每个长度执行另一个特定的调用并等待响应并存储结果以供稍后使用。
最后,我将调用更新客户端的名称,获取结果,然后与我之前有条件做出的所有响应合并。
将地址分为两组:要创建的和要更新的。
const addressesToBeCreated: Address[] = [ /* list of addresses to be created */ ];
const addressesToBeUpdated: Address[] = [ /* list of addresses to be updated */ ];
分别收集创建和更新地址所需的 HTTP 请求。 (假设服务器响应内容是什么。)
const createRequests: Observable<Address>[] = addressesToBeCreated.map(
(address) => this.client.post(...) // request server to save the address, and respond with the created address resource
);
const updateRequests: Observable<Address>[] = addressesToBeUpdated.map(
(address) => this.client.put(...) // request server to update existing address, and respond with the updated address resource
);
使用运算符 forkJoin
和 concatMap
构造一个管道,告诉 RxJS 实际触发发送创建和更新请求,然后 return表示已创建和更新的地址。
const savedAddresses$ = forkJoin(createRequests) // trigger the bunch of HTTP requests that creates addresses
.pipe(
concatMap((createdAddresses) => { // now we have a list of created addresses
return forkJoin(updateRequests) // next, trigger HTTP requests that updates addresses
.pipe(
map((updatedAddresses) => { // now we have the list of updated addresses
return [ // emit a tuple of created and updated addresses down the pipeline
createdAddresses,
updatedAddresses
];
})
);
})
);
savedAddresses$
将是一个可观察对象,它发出一个包含两个元素的数组:一个已创建地址列表和一个已更新地址列表。
最后再调用一次更改客户端名称。
const savedModels$ = savedAddresses$.pipe(
concatMap((savedAddresses) => {
return this.client.put(...) // request server to update client name, and return updated client model
.pipe(
map((updatedClient) => { // now we have the client object with updated name
return [updatedClient, ...savedAddresses]; // emit a tuple down the pipeline with three elements: client, list of created addresses, and list of updated addresses
})
);
})
);
savedModels$
将是一个 observable,它发出三个元素的数组:更新了名称的客户端模型、创建的地址列表和更新的地址列表。
至此,您终于可以“在这里手动合并所有内容”。您可以加入有关客户的数据,以及已创建和更新的地址。
updateClientAndClientAddresses(): Observable<Client> {
... // code from previous steps
return savedModels$.pipe(
map(([updatedClient, createdAddresses, updatedAddresses]) => {
return {
...updatedClient,
address: [
...createdAddresses,
...updatedAddresses
]
};
})
);
}
为了示例起见,假设我有一个名为客户端的实体:
interface Client {
id: number
name: string
address: Address[]
}
interface Address {
id: number
street: string
}
在这种情况下,我无法在同一调用中更新客户端的 name
和他的 addresses
。
相反,我需要:
- 勾选要创建的地址,然后一个一个创建(并存储后面要用到的值)
- 勾选要更新的地址,然后一一更新(并存储后面要用到的值)
- 最后再打电话给客户的名字。
所以我想做的是加入可以在一个可观察对象中有条件地发生的多个 http 调用。
这是我目前拥有的:
updateClientAndClientAddresses(): Observable<Client> {
return of({}).pipe(
******* Conditionally make all the create addresses calls *******
******* Conditionally make all the update addresses calls *******
******* Then make the update name call *******
switchMap(([updateNameResponse: Client, responseOfAllAddressesToBeCreated: Address, responseOfAllAddressesToUpdated: Address]) => {
// Ideally here I will have the results of all the calls made so far.
// Merge everything manually here
return {
...updateClientCallResponse,
addresses: [
...responseOfAllAddressesToBeCreated,
...responseOfAllAddressesToUpdated
]};
}),
)
}
只是为了加强: 在调用更新名称之前,我需要检查是否:
addressesToBeCreated.length
如果是,我需要对该数组的每个长度执行一个特定的调用,等待响应并存储结果以供稍后使用。
然后我需要检查是否:
addressesToUpdated.length
如果是,我需要对该数组的每个长度执行另一个特定的调用并等待响应并存储结果以供稍后使用。最后,我将调用更新客户端的名称,获取结果,然后与我之前有条件做出的所有响应合并。
将地址分为两组:要创建的和要更新的。
const addressesToBeCreated: Address[] = [ /* list of addresses to be created */ ]; const addressesToBeUpdated: Address[] = [ /* list of addresses to be updated */ ];
分别收集创建和更新地址所需的 HTTP 请求。 (假设服务器响应内容是什么。)
const createRequests: Observable<Address>[] = addressesToBeCreated.map( (address) => this.client.post(...) // request server to save the address, and respond with the created address resource ); const updateRequests: Observable<Address>[] = addressesToBeUpdated.map( (address) => this.client.put(...) // request server to update existing address, and respond with the updated address resource );
使用运算符
forkJoin
和concatMap
构造一个管道,告诉 RxJS 实际触发发送创建和更新请求,然后 return表示已创建和更新的地址。const savedAddresses$ = forkJoin(createRequests) // trigger the bunch of HTTP requests that creates addresses .pipe( concatMap((createdAddresses) => { // now we have a list of created addresses return forkJoin(updateRequests) // next, trigger HTTP requests that updates addresses .pipe( map((updatedAddresses) => { // now we have the list of updated addresses return [ // emit a tuple of created and updated addresses down the pipeline createdAddresses, updatedAddresses ]; }) ); }) );
savedAddresses$
将是一个可观察对象,它发出一个包含两个元素的数组:一个已创建地址列表和一个已更新地址列表。最后再调用一次更改客户端名称。
const savedModels$ = savedAddresses$.pipe( concatMap((savedAddresses) => { return this.client.put(...) // request server to update client name, and return updated client model .pipe( map((updatedClient) => { // now we have the client object with updated name return [updatedClient, ...savedAddresses]; // emit a tuple down the pipeline with three elements: client, list of created addresses, and list of updated addresses }) ); }) );
savedModels$
将是一个 observable,它发出三个元素的数组:更新了名称的客户端模型、创建的地址列表和更新的地址列表。至此,您终于可以“在这里手动合并所有内容”。您可以加入有关客户的数据,以及已创建和更新的地址。
updateClientAndClientAddresses(): Observable<Client> { ... // code from previous steps return savedModels$.pipe( map(([updatedClient, createdAddresses, updatedAddresses]) => { return { ...updatedClient, address: [ ...createdAddresses, ...updatedAddresses ] }; }) ); }