如何在 Nestjs 应用程序 w/o 控制器中使用 rxjs/Observables

How to use rxjs/Observables inside Nestjs Application w/o Controller

Nestjs suggests 使用从 @nestjs/axios 导入的 HttpModule 来执行对外部 API 的请求。 我知道 HttpService 将响应转换为 Observables.

目标

从外部请求数据API并在应用程序内部使用数据。

问题

我不明白如何从请求中实际检索数据。我在其他一些答案中读到,如果你 return 来自 Controller 的可观察对象,Nestjs 会自动为你处理它并 return 将数据发送给客户端。这很好,但是,我没有在 Controller 中使用它。我需要数据在应用程序内部可用。

我有一个服务:

@Injectable()
export class ExampleService {

  // constructor

  getData(): Observable<AxiosResponse<any[]>> {
    return this.httpService.get(`http://some-url.com`);
  }

}

如何在应用程序逻辑中使用 getData() 来获取由 Observable 编辑的数据 return?在这种情况下,使用带 Promises 的普通 axios 请求而不使用 HttpModule 会更好吗?

到目前为止我找到的唯一解决方案是使用 subscribe :

this.httpService.get(`http://some-url.com`)
.subscribe((value) => {
  console.log(value);
});

与所有花哨的东西相比,这似乎最终会陷入回调地狱 async ... awaits

答案

The only solution I found so far is using subscribe

宾果游戏。就是这样完成的:)

一些阐述

Which seems to be would end up in a callback hell, compared to all the fancy async ... awaits

不是真的。作为一个为声明式而构建的库,RxJS 可以轻松构建您的回调。

async/await 只是 promise.then 的语法糖。这是一种语言特性,但即使没有 async/await 承诺也能很好地相互绑定并避免深度嵌套和 'callback hell'

因此,虽然 observables 不会(而且可能永远不会)享受像 async/await 这样的拳头-class 语言结构,但这并不意味着它们不会管理一些(或很多)对你来说很复杂。


RxJS 库的构建使得一般情况下您永远不必嵌套订阅。

以下被认为是反模式:

stream1().subscribe(value1 => 
  stream2(value1).subscribe(value2 => {
    /* Do something with value2 */
  })
)

更惯用的写法是:

stream1().pipe(
  mergeMap(value1 => stream2(value1))
).subscribe(value2 => {
  /* Do something with value2 */
})

注意到如何删除缩进级别并且您只需要订阅一次吗?

Observables 带有一组高阶运算符,这些运算符充当高度可定制的 .then 值流而不仅仅是单个值。

另一种方式:转换为 Promise

Observables 是 promises 的超集,这意味着您可以将任何 promise 转换为 observable,但如果您想将 observable 转换为 promise,就会失去结构。通常这不是问题,但让我举个例子。

如果 promises 是一个值的容器,那么 observables 就是一个值列表的容器。

我可以取任何值并从中创建一个列表。我只有一个长度为 1 的列表。

value = 5
// convert with:
list_values = [a]

我无法获取任何列表并从中创建值。我可以取第一个值或最后一个值(如果只有一个,它们可能相同),如果列表为空,也许我需要抛出一个错误?也许有一个我会满意的默认值?

也许我有办法将多个值缩减为一个值。或许我可以通过将整数列表全部相加来将它们变成一个值。

list_values = [1,2,3,4,5]
// convert with:
value = list_values[0] || 0
// or
value = list_values[list_values.length - 1] || 100
// or
value = sum(list_values)

回到承诺。 RxJS 有 firstValueFromlastValueFrom 作为实用函数,将 promise 包装在可观察对象周围。

firstValueFrom(
  this.httpService.get(`http://some-url.com`)
).then(value => {
  /* Do something with value */
});

// or with await as syntactic sugar

value = await lastValueFrom(
  this.httpService.get(`http://some-url.com`)
);
/* Do something with value */

这些对于像 http 请求这样的东西通常已经足够了(因为那些只有 return 一个单一的值)。更复杂的方法倾向于在 RxJS 端处理,然后再转换为 promise。