【问题标题】:Getting errors trying to get observable from "observable's chain"尝试从“可观察的链”中获得可观察的错误
【发布时间】:2018-11-18 23:05:15
【问题描述】:

嗯。我的 Angular 组件中有一些异步代码,效果很好。看起来像这样(简要地):

export class SomeComponent {

    user: User;
    /* ... */
    email: string;
    /* ... */

    private someMethod(): void {
      /* some code here */
      this.userService1.getUsers().subscribe(users => {
        users.forEach(user => {
          if (user.email && user.email === this.email) {
             this.userService2.getUser(user.id).subscribe(foundUser => {
               let someFields;
               if (foundUser) {
                 someFields = (({ field1, field2 }) => ({ field1, field2 }))(foundUser); 
               }
               this.user = {...user, ...someFields};
             });
           }
         });
      });
      /*some code here */              
    }
 }

我跳过一些类型和命名变量有点尴尬(但很简单),因为这不是重点。代码有效。但是我想封装用户构建(来自 2 个服务)的过程,因为我需要在不同的组件中使用它。我试过了,但是……

constructUser(email): Observable<IUser> {
  let finalUser: IUser;

  return this.userService1.getUsers().merge(users => {
    return users.filter(user => {
      if (user.email && user.email === email) {
        return this.userService2.getUser(user.id).map(foundUser => {
          let someFields;
          if (foundUser) {
            someFields = (({ field1, field2 }) => ({ field1, field2 }))(foundUser); 
          }
          finalUser =  {...user, ...someFields};

          return Observable.of(finalUser);
        });
      }
    });
  });
}

我的 WebStorm 没有显示错误。但在控制台中我得到 this.userService1.getUsers(...).merge is not a function.

我已经尝试过 mergeconcatflatMap 等等 - 但仍然没有成功。唯一的区别是我遇到的错误。我对 rxjs 没有太多经验,所以我被卡住了。任何帮助或提示将不胜感激。

UPD。
已解决,但在 7 天(赏金活动期间)仍然欢迎任何人提供更简洁和实用的解决方案:)

【问题讨论】:

    标签: javascript angular functional-programming rxjs observable


    【解决方案1】:

    正确答案(跳过某些类型并更改变量的真实名称):

    非常感谢@Robin Dijkhof,他以正确的顺序为我提供了 rxjs 运算符

    public constructUser(email: string): Observable<User> {
      return this.userService1.getUsers().pipe(
        map(users => users.find(userInList => userInList.email === email)),
        switchMap(user => {
          return this.userService2.getUser(user.id).map(foundUser => {
            if (foundUser) {
              return {...user, ...(({ field1, field2 }) => ({ field1, field2 }))(foundUser)};
            } else {
              return {...user};
            }
          });
        })
      );
    }
    

    现在我可以轻松地使用该方法在任何组件中通过电子邮件(也许稍后我会用 id 替换电子邮件)来获取构建的用户,例如:

    this.myHelperService.constructUser(email).subscribe(user => {...});
    

    我认为可以使解决方案更加实用和简洁(也许解决方案必须更加健壮)...
    所以!欢迎任何人,50 额外奖励积分仍然存在 7 天 =)

    【讨论】:

    • 第二张地图应该和第一张一样使用管道。
    • 它也适用于地图...好吧,我必须更好地学习 Rxjs 以找出差异:)
    【解决方案2】:

    我认为你想要这样的东西:

    RxJs 5:

    import 'switchMap' from 'rxjs/add/operator/switchMap';
    import 'map' from 'rxjs/add/operator/map';
    
    
    this.userService1.getUsers()
        .map(users => users.find(userInList => userInList.email === "SomeEmail")) //Map the observable with users to a single user
        .switchMap(user => this.userService2.getUser(user.id)) //Map the observable by an other observable
        .subscribe(...doSomething with the result)
    

    RxJs 6:

    import {map, switchMap} from 'rxjs/operators';
    
    this.userService1.getUsers().pipe(
        map(users => users.find(userInList => userInList.email === "SomeEmail")), //Map the observable with users to a single user
        switchMap(user => this.userService2.getUser(user.id)) //Map the observable by an other observable
    ).subscribe(...doSomething with the result)
    

    【讨论】:

    • 谢谢你,伙计,我想它非常接近正确答案,现在我正在尝试实现它。如果我成功了——我会接受你的尝试:)
    【解决方案3】:

    我认为你应该在做任何其他事情之前订阅

    this.userService1.getUsers().subscribe(users => {...
    

    【讨论】:

    • 在直接订阅中做所有事情完全消除了 RxJs 的力量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多