繁体   English   中英

如何使用 RxJS 并行化多个 HTTP 调用

[英]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'},
]

对了,顺序如下:

  1. 获取 A 公司的地址并存储 ID
  2. 获取 A 公司的链接
  3. 循环遍历每个链接 3a。 获取链接 3b 的地址。 检查地址 ID 是否与 A 公司的地址 ID 匹配。 如果是,请存储链接。

当前实施

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM