Angular 服务的方法是否应该始终 return 可观察?
Should Angular services' methods always return observables only?
我是 observables 的新手,我很难理解如何正确使用它们。
说我有这个服务:
class MyService {
query() {
return from(myApiCall()).pipe(
pluck('data'),
mergeMap(apiResponse => {
const obj = apiResponse.foo.map(el => {
return {
bar: el.bar,
otherProp: el.baz,
// how do I get the litteral value here and not an observable?
builtProp: this.buildProp(el.myProp)
}
})
return obj
)
}
buildProp(value) {
if(!value) {
return throwError('value missing')
}
return of(`the value is: ${value}`)
}
}
buildProp
是一个 public 方法,我希望可以选择从 MyService
class 之外的其他地方调用它。它的作用没有任何异步,所以它也可以直接 return 值而不是可观察值。但是,如果 MyService
return observables 的某些方法和其他方法没有,那么使用起来可能会不一致且烦人。
我想到了一个私有方法 returns 构建对象时使用的纯字符串,还有另一个 public 方法 returns of(buildProp(val))
,但这感觉很笨拙(不要介意现在为这两种不同的方法找到好名字的困难)。
Angular 服务上的任何 public 方法是否应该总是 return 可观察的,即使该方法的作用没有任何异步?
在那种特殊情况下,我如何以优雅且惯用的 Angular 方式在 returned 对象中获取文字字符串而不是 builtProp
的可观察值?
我喜欢在 Angular 中思考服务的方式是它们是放置任何类型的业务逻辑的地方,从复杂的异步内容到简单的数据同步转换。
为什么要将逻辑放在服务中?一个很好的理由是,这使代码更易于测试,并迫使您仅在组件中保留与可视化和管理用户交互严格相关的内容。
话虽如此,但没有理由认为服务必须 return Observables。他们必须 return 对 return 有意义的东西:异步逻辑情况下的 Observable,其他同步情况下合适的任何其他内容。
这里有一些关于您的具体案例的思考。
首先我质疑为什么要使用mergeMap?您应该可以使用 map
获得相同的结果,这是一个对源 Observable 发出的数据执行转换的运算符。换句话说,我希望这种使用 map
并且不需要 buildProp
到 return Observable 的逻辑能够工作。
class MyService {
query() {
return from(myApiCall()).pipe(
pluck('data'),
map(apiResponse => {
const obj = apiResponse.foo.map(el => {
return {
bar: el.bar,
otherProp: el.baz,
builtProp: this.buildProp(el.myProp)
}
})
return obj
)
}
buildProp(value) {
if(!value) {
return throwError('value missing')
}
return `the value is: ${value}`
}
}
第二点是关于何时使用mergeMap
和其他类似的运算符,如switchMap
、exaustMap
、concatMap
,它们都是接受作为输入函数的运算符 returning 另一个 Observables。
此类运算符用于“扁平化”内部 Observable 并最终创建一个 Observable,该 Observable 会发出内部 Observable 发出的数据。使用示例可能更容易解释这个概念。假设您必须调用第一个 Rest API(通过 http 的异步调用)并使用数据 returned 作为输入来调用第二个 Rest API。要处理这种情况,您应该编写类似这样的代码
firstApi().pipe(
concatMap(firstResult => secondApi(firstResult)
).subscribe(
// secondResult is the result returned by the invocation of secondApi
secondResult => {// do stuff with secondResult}
)
在这种情况下,如果您使用 map
而不是 concatMap
(这在某种程度上类似于您的 mergeMap),您会看到发出 Observable 而不是 [=21= 的结果],这不是你想要的。
如果您想阅读更多有关 RxJs 在 http 场景中的典型使用模式的详细信息,可以look at this article。
我是 observables 的新手,我很难理解如何正确使用它们。
说我有这个服务:
class MyService {
query() {
return from(myApiCall()).pipe(
pluck('data'),
mergeMap(apiResponse => {
const obj = apiResponse.foo.map(el => {
return {
bar: el.bar,
otherProp: el.baz,
// how do I get the litteral value here and not an observable?
builtProp: this.buildProp(el.myProp)
}
})
return obj
)
}
buildProp(value) {
if(!value) {
return throwError('value missing')
}
return of(`the value is: ${value}`)
}
}
buildProp
是一个 public 方法,我希望可以选择从 MyService
class 之外的其他地方调用它。它的作用没有任何异步,所以它也可以直接 return 值而不是可观察值。但是,如果 MyService
return observables 的某些方法和其他方法没有,那么使用起来可能会不一致且烦人。
我想到了一个私有方法 returns 构建对象时使用的纯字符串,还有另一个 public 方法 returns of(buildProp(val))
,但这感觉很笨拙(不要介意现在为这两种不同的方法找到好名字的困难)。
Angular 服务上的任何 public 方法是否应该总是 return 可观察的,即使该方法的作用没有任何异步?
在那种特殊情况下,我如何以优雅且惯用的 Angular 方式在 returned 对象中获取文字字符串而不是 builtProp
的可观察值?
我喜欢在 Angular 中思考服务的方式是它们是放置任何类型的业务逻辑的地方,从复杂的异步内容到简单的数据同步转换。
为什么要将逻辑放在服务中?一个很好的理由是,这使代码更易于测试,并迫使您仅在组件中保留与可视化和管理用户交互严格相关的内容。
话虽如此,但没有理由认为服务必须 return Observables。他们必须 return 对 return 有意义的东西:异步逻辑情况下的 Observable,其他同步情况下合适的任何其他内容。
这里有一些关于您的具体案例的思考。
首先我质疑为什么要使用mergeMap?您应该可以使用 map
获得相同的结果,这是一个对源 Observable 发出的数据执行转换的运算符。换句话说,我希望这种使用 map
并且不需要 buildProp
到 return Observable 的逻辑能够工作。
class MyService {
query() {
return from(myApiCall()).pipe(
pluck('data'),
map(apiResponse => {
const obj = apiResponse.foo.map(el => {
return {
bar: el.bar,
otherProp: el.baz,
builtProp: this.buildProp(el.myProp)
}
})
return obj
)
}
buildProp(value) {
if(!value) {
return throwError('value missing')
}
return `the value is: ${value}`
}
}
第二点是关于何时使用mergeMap
和其他类似的运算符,如switchMap
、exaustMap
、concatMap
,它们都是接受作为输入函数的运算符 returning 另一个 Observables。
此类运算符用于“扁平化”内部 Observable 并最终创建一个 Observable,该 Observable 会发出内部 Observable 发出的数据。使用示例可能更容易解释这个概念。假设您必须调用第一个 Rest API(通过 http 的异步调用)并使用数据 returned 作为输入来调用第二个 Rest API。要处理这种情况,您应该编写类似这样的代码
firstApi().pipe(
concatMap(firstResult => secondApi(firstResult)
).subscribe(
// secondResult is the result returned by the invocation of secondApi
secondResult => {// do stuff with secondResult}
)
在这种情况下,如果您使用 map
而不是 concatMap
(这在某种程度上类似于您的 mergeMap),您会看到发出 Observable 而不是 [=21= 的结果],这不是你想要的。
如果您想阅读更多有关 RxJs 在 http 场景中的典型使用模式的详细信息,可以look at this article。