Angular 应提供角度服务';方法总是只返回可观察的?

Angular 应提供角度服务';方法总是只返回可观察的?,angular,rxjs,observable,Angular,Rxjs,Observable,我是一个新的观察者,我很难理解如何正确使用它们 假设我有这项服务: class MyService { query() { return from(myApiCall()).pipe( pluck('data'), mergeMap(apiResponse => { const obj = apiResponse.foo.map(el => { return { bar: el.bar,

我是一个新的观察者,我很难理解如何正确使用它们

假设我有这项服务:

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
是一个公共方法,我希望可以从
MyService
类之外的其他地方调用它。它所做的事情并不异步,因此它最好直接返回值,而不是一个可观察的值。但是,如果
MyService
的某些方法返回可观测值,而其他方法则不返回可观测值,那么使用这种方法可能会不一致,而且会很烦人

我曾想过使用一个私有方法,返回构建对象时要使用的普通字符串,以及另一个公共方法,返回of(buildProp(val)),但这感觉很笨拙(尽管现在很难为这两个单独的方法找到好的名称)

Angular服务上的任何公共方法是否应该总是返回一个可观察的,即使该方法的功能没有任何异步性


在这种特殊情况下,我如何以优雅而惯用的角度在返回对象中获得文本字符串而不是可观察的
builtProp

我喜欢用角度思考服务的方式是,它们是放置任何业务逻辑的地方,从复杂的异步数据到简单的数据同步转换

为什么要将逻辑放在服务中?一个很好的原因是,这使代码测试变得更加简单,并迫使您只保留与可视化和管理用户交互严格相关的组件

话虽如此,我们没有理由认为服务必须返回可观察的结果。它们必须返回有意义的返回:在异步逻辑的情况下是可观察的,在其他同步情况下是适当的

下面是一些关于您的具体案例的思考

首先,我问为什么要使用mergeMap?您应该能够使用
map
实现相同的结果,这是一个对源可观测数据发出的数据执行转换的操作符。换句话说,我希望这个逻辑能够工作,它使用
map
,并且不需要
buildProp
来返回一个可观察的对象

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
,这些操作符都接受作为输入函数返回另一个观察值

此类操作符用于“展平”内部可观测对象,并最终创建一个可观测对象,该可观测对象发出内部可观测对象发出的数据。用一个例子来解释这个概念可能更容易。假设您必须调用第一个REST API(通过HTTP进行异步调用),并使用返回的数据作为输入来调用第二个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),您将看到发出的是一个可观察对象,而不是
secondApi
的结果,这不是您想要的结果


如果您想了解更多关于http场景中使用RxJs的典型模式的详细信息,可以。

AFAIK,没有硬性规定服务应该包含只返回可观察的方法。另外,
builtProp:String(el.myProp)
不会直接返回字符串值吗?这不起作用,它返回[object]
var rxjs=require(“rxjs”)const value$=rxjs.of('hello')const value=String(value$)console.log({value})/=>“[object object]”
这是字符串原型,
String(…)
实例化一个新字符串。将对象转换为字符串通常会导致非常无用的
“[object object]”
。它是一个对象,因为这就是未订阅的可观测值。一个字符串,我在
buildProp
中插入另一个字符串。为什么要将该字符串转换为可观测值?你不需要把它当作一根绳子吗?