如何在 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 有 firstValueFrom
和 lastValueFrom
作为实用函数,将 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。
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 有 firstValueFrom
和 lastValueFrom
作为实用函数,将 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。