angular - 如何最好地处理角度模型中的嵌套请求而不等待嵌套请求完成
问题描述
我们的 Angular 应用程序的 API 有很多由 href 引用的嵌套对象。我正在尝试将所有这些响应映射到模型,以在后端和前端之间进行一些解耦。但是,我遇到了这些嵌套 href 的问题。
这是来自服务器的示例响应:
First response:
{
"firstName": "Steve",
"lastName": "Mcqueen",
"account": "api/path/account/some-id-key"
}
我的问题是:如何处理获取帐户的请求。在某些情况下可能有 3-4 个(或者更糟糕的是,位于 2-3 层深),我并不总是立即需要这些数据。最好由服务(在本例中为 AccountService)处理请求。
我考虑了几种方法。第一个也是最懒惰的是在模型中简单地将 href 存储为字符串并在需要的地方获取它。
class Client {
firstName: string;
lastName: string;
account: string;
}
// in a component
this.clientService.getClient(id).subscribe(client => {
this.accountService.getAccount(client.account).subscribe(...)
})
但是,我担心这会变得非常混乱。每次更新客户端时,四个不同的组件现在可能同时执行相同的请求。到处都有这些订阅者也不是很好看。
其次,我考虑让服务使用 tap、switchmap 进行所有获取,就像在这个答案中一样。
这里的问题是我必须等待模型中的每个请求都得到解决,然后才能开始显示任何数据。如果它像上面的例子那样很好,但情况并非总是如此。
最好的情况是,如果我能以某种方式让模型拥有 Observables 而不是 hrefs。所以客户端模型看起来像
class Client {
firstName: string;
lastName: string;
account: Observable<Account>;
}
// in a component
this.clientService.getClient(id).subscribe(client => {
client.account.subscribe(...) // no more duplicated requests
})
// In the model adapter
adapt(data) {
return new Client(
data.firstName,
data.lastName,
this.accountService.getAccount(data.account)
)
}
但是,我正在努力解决如何最好地映射它。由于每个请求都会创建一个新模型,因此最终会导致泄漏,因为“旧”模型不会被取消订阅。除非该服务会以某种方式为相同的模型 href 重用相同的 observable 吗?
解决方案
也许你需要这样的东西:
您的客户服务:
import { Injectable } from '@angular/core';
import { Observable, of, BehaviorSubject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { map, first } from 'rxjs/operators';
class Client {
firstName: string;
lastName: string;
account: Observable<any>;
}
@Injectable({
providedIn: 'root',
})
export class ClientService {
// Keep your client list in memory. only hit api one time per client.
private clientList = {};
constructor(private http: HttpClient) {}
getClient(id: string): Observable<Client> {
// if have client in memory return a observable of that client.
if (this.clientList[id]) {
return of(this.clientList[id]);
}
const url = `http://my_api/clients/${id}`;
// hit the api to ge the client data.
return this.http.get(url).pipe(
map((resp: any) =>
// builder Method only return the client Instance.
this.createClient(id, resp.firstName, resp.lastName, resp.accountUrl),
),
);
}
private createClient(id, firstName, lastName, accountUrl): Client {
// BehaviorSubject its a Obvservable that keep the last value emitted in memory
// when someone subscribe to him, he emit the last value.
const subject = new BehaviorSubject(null);
// subject.asObservable() this method make a Subject as Observable. To block emit method outside this clase.
const client = { firstName, lastName, account: subject.asObservable() };
// call to api to get the account data.
this.http
.get(accountUrl)
.pipe(first()) // first operator get the first value emited and unsubscribe.
.subscribe(accountData => subject.next(accountData)); // emiit the accountn data.
this.clientList[id] = client;
return client;
}
}
在您的组件中声明一个客户端属性。
client: Client;
调用服务
this.clientService
.getClient('21')
.subscribe(client => (this.client = client));
在您的 html 中查看数据:
{{client.firstName }}
{{client.lastName }}
{{client.account | async | json }}
这样。您可以显示客户的数据,而无需等待帐户的数据。并为客户数据点击一次api,为客户帐户点击一次。如果您在许多组件之间共享服务,您将返回 clientList Attr 的客户端,而不是再次调用 api。
推荐阅读
- javascript - Onclick 事件:单击浏览器上下文菜单时导航到当前选项卡中的页面(在 FF 插件中)
- javascript - 如何使用 fetch 处理响应 .json 和 .text?
- sql - 如果 CSV 没有所有表格字段,如何将 CSV 导入表格?
- javascript - React 中的 PrivateRouter 组件
- apache-kafka-streams - 如何为spring kafka流中的多个绑定设置UncaughtExceptionHandlers?
- python - 如何显式查找构建的 Tensorflow 模型并提取模型预测
- google-apps-script - 如何在 AppMaker 的 MultiSelect 小部件中手动设置值?
- python - 如何在我的项目中正确加载 Python 类?
- r - 如何使用 Slurm 在多个节点上发送循环?
- excel - 如何按单独的列有条件地排序?