![](/img/trans.png)
[英]Using rxjs forkjoin and angular 10 http interceptor, how do I exchange only 1 refresh token with multiple http calls?
[英]How do I parallelise multiple HTTP calls using RxJS
背景
我正在构建一个 Angular 应用程序,它列出了在给定地址注册的公司。
给出一些上下文...
假设我有 x3 家公司:A 公司、B 公司和 C 公司。
B 公司的注册地址与 A 公司相同。C 公司不是。
当我导航到应用程序并筛选公司 A 时,我希望在列表中只看到公司 B。
问题
我的问题不是我不能让它工作,它太慢了! 我需要以某种方式利用多线程/并发。
为了确定在给定地址注册了哪些公司,我必须进行几次 HTTP 调用。
在解释我进行 HTTP 调用的顺序之前。 让我向您展示 API 的样子:
GET /api/companies/CompanyA/address
{
id: 1,
addressLine1: '123 Some street',
...
}
GET /api/companies/CompanyA/links
[
{id: 2, name: 'Company B'},
{id: 3, name: 'Company C'},
]
对了,顺序如下:
当前实施
const companyAId: number = 1;
const companyAAddress: Object = await this.httpService.getAddress(companyAId).toPromise();
const companyALinks: Object[] = await this.httpService.getLinks(companyAId).toPromise();
const companiesToShow: Object[] = [];
for (let link of links) {
const linkAddress: Object = await this.httpService.getAddress(link ['id']).toPromise();
if (linkAddress['id'] === companyAAddress['id']) companiesToShow.push(link );
}
必须有一个更优雅/高性能的解决方案!
任何帮助将不胜感激 :)
谢谢,
本
您是正确的,因为这些 API 调用中的每一个都必须先等待另一个调用完成。
您本身无权访问多线程,但您可以使用Promise.all
使其并发,就像您编写的那样。 具体来说,您可以同时检索地址和链接,然后同时检索所有其他地址。 我缩短了一些方法调用名称以使其更易于编写:
const [companyAAddress, companyALinks] = await Promise.all(
getAddress(id).toPromise(),
getLinks(id).toPromise(),
);
const companiesToShow = await Promise.all(links.map(link => getAddress(link.id).pipe(
map(linkAddress => [link, linkAddress]),
filter(([, { id }]) => id === companyAAddress.id),
).toPromise())
您可以严格地使用 Observables 来做到这一点,而不是使用承诺,这将使其可取消。
forkJoin(getAddress(id), getLinks(id)).pipe(
mergeMap(([companyAAddress, companyALinks]) => companyALinks.map(link => getAddress(link.id).pipe(
map(linkAddress => [link, linkAddress]),
filter(([, { id }]) => id === companyAAddress.id),
))
)
但是,我会说从单个请求中获取链接公司的能力应该由服务器实现。
您应该在这里考虑另一种布局。
选项1
将该业务逻辑移至服务器端。 从您对问题的描述中,我看不出客户端以任何方式简化了检索 B 的地址的操作。 服务器端拥有检索所有链接地址所需的所有信息。
您只需要对后端进行一次调用。 并且您将避免await
这里await
,如果服务器没有快速响应,这会使用户的触觉也变慢。
服务器端的伪代码:
// this is a new endpoint on the backend which holds your current client logic
on(/api/companies/<company>/address_links) {
// retrieve the address with it's id like your first endpoint and store it temporary in address/id
address = getCompanyAddress(company);
// query all all addresses with that id/address and store it in links[]
other_companies[] = getCompaniesWithAddress(address);
// Build your response JSON
return_me = {
id: address.id,
addressLine1: address.line1,
links: other_companies
}
// send the response
response.send(return_me);
}
选项 2
重新设计后端并使用 websockets 加速查询。 您还可以绕过同时 HTTP 请求的限制(每个服务只有一个)。
如果连接尚未建立,但比多个 HTTP 请求的开销要小得多,Websockets 对于单个请求可能会更慢。 可以在这里找到一篇非常好的文章(来自一个非常好的框架 FeathersJS 的作者): https : //blog.feathersjs.com/http-vs-websockets-a-performance-comparison-da2533f13a77
您更改组件代码以收听观察者
this.subscription = this.myService.addressObserver$.subscribe((data: any) => {
[Assign and do something]
}
并将服务更改为使用套接字(不完整且不可运行,仅举个例子):
import * as feathers from '@feathersjs/client';
import * as io from 'socket.io-client';
[...]
@Injectable()
export class MyService {
private readonly feathersService: any;
public myObserver$: Subject<any>;
constructor() {
const socket = io(<url>, {
transports: ['websocket'],
forceNew: true,
});
const feathersApp = feathers().configure(feathers.socketio(socket));
this.feathersService = feathersApp.service('api/address');
// on (create, delete, update) methods work like realtime when something changed on the server
this.feathersService.on('updated', (address) => this.onUpdated(address));
}
// single find, can be adapted to query by something
public find(): void {
// the actual query to the server
this.feathersService.find(address).then((addresses: any) => {
this.myObserver$.next(addresses.data);
});
}
...
选项 3
两者都做
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.