【问题标题】:Angular 5 Observable, return when completeAngular 5 Observable,完成后返回
【发布时间】:2018-12-18 11:46:09
【问题描述】:

帮助 Angular 5 Observables。

我想对控制器隐藏复杂性;也就是说,它不必订阅 observable。拥有服务中的所有复杂性,并让它简单地将结果/有效负载返回给组件。但显然我陷入了时间问题。我觉得这应该是一个流行的事情/话题,但还没有找到答案。所以也许我做错了什么?

//in the component.ts
const allColors = this.auth.getColors(); //service call
console.log(allColors); // returns undefined

//in the service.ts
getColors() {
  var myColors = "";

  var colors = this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
    .pipe(catchError(this.handleError));

  //
  colors.subscribe(
    res => {
      myColors = res.body;
    },
    error => {}
  );

  return myColors;
}

【问题讨论】:

  • 您无法简化到这一点。服务应该返回 observable 本身。您可以在需要结果的地方订阅它,并在订阅回调中使用返回的值。
  • 我认为拥抱 Observables 比绕过它们更好,因为它们是 Angular 工作方式不可或缺的一部分(以及其他原因)。当它实际上是一个异步过程时,您似乎正试图使其行为同步。
  • 每次发出 http 请求时,您想要做的基本上都是阻止整个应用程序的执行。
  • 请注意,您仍然可以隐藏一些复杂性,这样服务的用户就不必处理http 调用和res.body(借助@ 987654325@运营商)。

标签: angular observable


【解决方案1】:

我认为你不能做你想做的事,因为在你的服务中的订阅没有得到解决之前,它不会向组件发送任何东西,在组件的执行中它是未定义的,因为响应没有'还没来。

这就是发明回调函数的原因。正确的做法是在您的组件中订阅,因为您想等待服务的响应。

对不起,我还不能使用 cmets,所以我不得不做出这个回复。希望对你有帮助

【讨论】:

    【解决方案2】:

    脱离了 Osakr 所说的。您必须订阅您的组件。

    在你的 service.ts 中

    getColors(): Observable<any> {
    
        let urlString = 'http://localhost/Account/GetColors'
    
        return this.http.get(urlString);
      }
    

    在你的组件中:

    getColors() {
    
        this.service.getColors()
          .subscribe((colors) => {
    
          this.myColors = colors;
    
      })
    }
    

    【讨论】:

      【解决方案3】:

      你的方法什么时候返回?这是您需要回答的问题,并且为了避免悬念,它会返回 之前 myColors 被任何东西填充,这就是异步编程的本质。

      你需要返回 observable 并让它在结果可用时通知你。这种复杂性不能以您尝试的方式隐藏,您可以得到的最接近的方法是将回调函数传递给您的服务方法,然后在结果可用时调用该方法,如下所示:

      getColors(callback) {
          //...
      
          colors.subscribe(
             res => {
                 callback(res.body);
             }
             //...
          );
      }
      

      但是你会错过很多很酷的功能,例如能够将multiple subscribers 用于同一个可观察对象。

      【讨论】:

        【解决方案4】:

        所以也许我做错了什么?

        确实如此。使用 Observables 和 Promises 拥抱异步编程。我相信这是你问这个问题的唯一原因,你不完全理解它们是如何工作的,所以你想把它抽象出来,这是你做不到的。另见How do I return the response from an asynchronous call?


        也就是说您可以使用async/await,它可以提供同步代码的外观

        component.ts

        async ngOnInit() {
          const allColors = await this.auth.getColorsAsync(); //service call
          console.log(allColors); // returns color array
        }
        

        service.ts

        getColorsAsync(): Promise<color[]> {
          return this.http.get<color[]>('http://localhost/Account/GetColors', httpOptions)
            .pipe(catchError(this.handleError))
            .toPromise();
        }
        

        我猜到了实际的类型。理想情况下,您应该尽可能使用强类型

        【讨论】:

          【解决方案5】:

          我认为你可以用不同的方式做到这一点

          //in the component.ts
          this.service.getColors(); //service call
          console.log(this.service.allColors); // print the service property.  which will resolve after the oberservable resolve
          
          //in the service.ts
          @injectable()
          export class Service {
            public allColors: any; //Public property to print.
            public getColors() {
              var myColors = "";
          
              var colors = this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
              .pipe(catchError(this.handleError));
          
              colors.subscribe(
                res => {
                   this.allColors= res.body;
                },
                error => {}
               );
          
              return;
            }
          }
          

          【讨论】:

            【解决方案6】:

            我会这样做:

            this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
              .pipe(catchError(this.handleError))
              .subscribe(res => {
                console.log(res.body);
              });
            

            【讨论】:

              【解决方案7】:

              您想在使用服务之前使用Resolver 和路由来预加载数据。

              解析器是在激活其余路由之前完成的异步操作。因此,您将定义一个 top-level 路由,它不做任何事情,但包含用于获取颜色数据的解析器。我说 顶级 因为我认为这是全局应用程序数据。如果此数据特定于某个功能,则将解析器放置在正确的路由路径中。

              const routes: Routes = [
                  { 
                     path: '',
                     resolve: {
                         Colors: ColorsResolver
                     },
                     children: [
                           // your application routes here
                     ]
                  }
              ] 
              

              ColorsResolver 类将从服务器获取颜色数据,然后将其分配给服务。

              @Injectable()
              export class ColorsResolver implements Resolve<any> {
                   public constructor(private colorService: ColorService) {}
              
                   public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
                        return this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
                                .do((resp)=> this.colorService.setColor(resp));;
                   }
              }
              

              在您的服务中,您只需将值分配给属性

               @Injectable()
               public ColorService {
                   public setColor(resp: any) { this._color = resp; }
                   public getColor():any { return this._color; }
               }
              

              您现在可以在解析器完成后多次调用getColor() 而不会阻塞。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-09-15
                • 2021-08-25
                • 1970-01-01
                • 2021-06-20
                • 2018-12-20
                • 2018-09-14
                • 2018-07-08
                • 2021-09-24
                相关资源
                最近更新 更多