代码之家  ›  专栏  ›  技术社区  ›  Johan Rin

链接到重构的两个订阅

  •  2
  • Johan Rin  · 技术社区  · 6 年前

    我试图用两个订阅(一个在方法中,一个在服务中)来重构下面的代码,但我找不到一种方法来实现这一点。

    我正在使用 akita 处理我的状态。因此,建议在服务中使用订阅,如中所述 documentation .

    此代码用于处理非规范化的情况:MongoDB服务集合中用户集合的my language字段。

    以下是我使用的模型:

    用户模型

    export interface UserInfo {
      [...]
      services: ID[];
    }
    
    export interface User {
      _id: ID;
      [...]
      userInfo: Partial<UserInfo>;
    }
    

    服务模式

    export interface ServiceInfo {
      [...]
      userFamilyName: string;
      userGivenName: string;
      userLanguages: Language[];
    }
    
    export interface Service {
      _id: ID;
      [...]
      serviceInfo: Partial<ServiceInfo>;
    }
    

    用我的方法

    private addLanguage(languageForm: FormGroup) {
    
      [...]
    
      this.usersService.addLanguage(user).pipe(
        takeUntil(this.ngUnsubscribe)
      ).subscribe(
        (entity: User) => {
          if (entity.userInfo.services) {
            entity.userInfo.services.forEach(serviceId => {
              const service = createService({
                _id: serviceId,
                serviceInfo: {
                  userLanguages: [language]
                }
              });
    
              this.servicesService.addLanguage(service); <--- have also a subscribe in its method
            })
          }
    
          languageForm.reset();
          this.onNavigateBack();
        }
      );
    }
    

    在服务中

    addLanguage(service: Service) {
      const url = `${this.servicesUrl}/${service._id}/languages`;
      const accessToken = this.authQuery.getSnapshot().accessToken;
      this.http.post<Service>(url, service, {
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
          'Authorization': accessToken
        })
      }).subscribe(
        (entity: Service) => {
          if (this.servicesQuery.hasEntity(service._id)) {
            this.servicesStore.update(service._id, entity);
          }
        }
      );
    }
    

    我到目前为止所做的尝试:

    this.usersService.addLanguage(user).pipe(
      filter((entity: User) => entity.userInfo.services !== undefined),
      switchMap((entity: User) => {
        entity.userInfo.services.forEach(serviceId => {
          const service = createService({
            _id: serviceId,
            serviceInfo: {
              userLanguages: [language]
            }
          });
    
          return this.servicesService.addLanguage(service);
        })
      }
    );
    

    但我被困是因为 entity.userInfo.services.forEach .

    有办法吗?

    谢谢你的帮助。

    1 回复  |  直到 6 年前
        1
  •  2
  •   CozyAzure    6 年前

    每当您在服务中看到订阅时,代码可能有问题。你需要使用 .tap() 做一些副作用的操作。从不订阅服务,让组件处理订阅。

    在职:

    addLanguage(service: Service) {
        const url = `${this.servicesUrl}/${service._id}/languages`;
        const accessToken = this.authQuery.getSnapshot().accessToken;
        this.http.post<Service>(url, service, {
            headers: new HttpHeaders({
                'Content-Type': 'application/json',
                'Authorization': accessToken
            })
        })
            .pipe(
                tap((entity: Service) => {
                    if (this.servicesQuery.hasEntity(service._id)) {
                        this.servicesStore.update(service._id, entity);
                    }
                })
            );
    }
    

    但是,在组件中,可以使用 filter() 和A switchMap() rxjs . 的诀窍 forEach ,是你用的吗? .map() 来自本机javascript数组函数。在你创建了这样的观察数组之后,你可以使用 forkJoin() 要组合它们并使它们平行发射:

    组件中:

    private addLanguage(languageForm: FormGroup) {
        this.usersService.addLanguage(user).pipe(
            takeUntil(this.ngUnsubscribe),
            //filter away the conditions  
            filter((entity: User) => entity.userInfo.services),
            switchMap((entity: User) => {
                //use .map() to create an array of services.
                let serviceObs$ = entity.UserInfo.services.map(serviceId =>
                    this.servicesService.addLanguage(createService({
                        _id: serviceId,
                        serviceInfo: {
                            userLanguages: [language]
                        }
                    })));
                //use forkJoin to combine all of them
                return forkJoin(serviceObs$);
            })
        ).subscribe(() => {
                languageForm.reset();
                this.onNavigateBack();
            }
        );
    }