嵌套的observable仅在超时后传播错误

时间:2017-01-07 07:44:00

标签: javascript angular rxjs observable

我的组件中有一个方法,它使用observable来监听第一个事件,并且超时为15秒。该方法调用嵌套的observable,如果参数为null或为空,则应抛出该错误。我使用Observable.throw()但错误仅在超时/ 15s之后传播。

this.signUp(this.user)
            .first()
            .timeout(15000)
            .subscribe((authResponse) => {
                console.log("next fired");
                dialogs.alert("Next: " + authResponse);
            }, (error) => {
                //fired only after 15s when mobile is empty
                console.log("error fired");
                console.log(JSON.stringify(error));
            }, () => {
                console.log("completed fired");
            });

注册()

public signUp(user: User): Observable<AuthResponse> {
        let observable = new Subject<AuthResponse>();
        this.isUserExisting(user.mobile)
            .first()
            .subscribe((isUserExisting) => {
                if (isUserExisting) {
                    console.log("User already exists");
                    observable.next(AuthResponse.USER_EXISTING);
                } else {
                    console.log("User does not exist");
                    this.saveUser(user).first().subscribe(() => {
                        observable.next(AuthResponse.SUCCESS);
                    })
                }
            }, (error) => {
                return Observable.throw(error);
            })
        return observable;
    }

    public isUserExisting(mobile: string): Observable<boolean> {
        let observable = new Subject<boolean>();
        if (!mobile) {
            console.log("empty mobile");
            return Observable.throw(new Error("Mobile number cannot be empty"));
        }
        firebase.query(() => { }, "/users",
            {
                singleEvent: true,
                orderBy: {
                    type: firebase.QueryOrderByType.CHILD,
                    value: "mobile"
                },
                range: {
                    type: firebase.QueryRangeType.EQUAL_TO,
                    value: mobile
                }
            }
        ).then((result) => {
            console.log("Checking for user success: ");
            console.log(JSON.stringify(result));
            observable.next(result.value != null);
        });
        return observable;
    }

更新: saveUser()

public saveUser(user: User) {
        return Observable.defer(() => firebase.push('/users', user)
            .then((result) => {
                console.log("Created user record with key: " + result.key);
                console.log("Dumping result:");
                console.log(JSON.stringify(result));
            })
            .catch((error) => {
                console.log("Error while saving user: " + error);
            })
        )
    }

1 个答案:

答案 0 :(得分:1)

创建您自己的主题是一种不好的做法,您将在该主题上发出由内部订阅的observable发出的可观察值。这会导致内存泄漏,因为您无法取消订阅内部订阅。

public signUp(user: User): Observable<AuthResponse> {
  return this.isUserExisting(user.mobile)
    .flatMap(isExistingUser => {
      if (isExistingUser) {
        console.log('user already exists: ' + isUserExisting);
        return Rx.Obserable.of(AuthResponse.USER_EXISTING);
      }
      return saveUser(user).map(result => AuthResponse.SUCCESS)
    })
    .catch(err => {
      console.log(`error during signup of user: ${user.mobile})`);
      return Rx.Observable.of(AuthResponse.FAILED_TO_SIGNUP);
    })
    .first();
}

如果您的signUp函数没有订阅,您的代码就可以取消订阅,错误会在没有任何工作的情况下传播。这也是您的超时而不是您的超时的原因手机号码检查;你忘了传播错误。相反,您尝试从Rx.Observable.throw回调中返回subscribeOnError,该回调的签名为onError(error):void

一个好的做法是让你的Rx功能保持懒惰;只有在有人订阅时才执行代码。这有助于减少难以跟踪的错误。在您的情况下使用firebase.query()(返回一个promise),您可以使用.defer()等待执行promise,直到有人订阅您的isUserExisting函数。

public isUserExisting(mobile: string): Observable<boolean> {
  if (!mobile) {
      console.log("empty mobile");
      return Observable.throw(new Error("Mobile number cannot be empty"));
  }

  return Rx.Observable.defer(() => firebase.query(() => { }, "/users",
      {
          singleEvent: true,
          orderBy: {
              type: firebase.QueryOrderByType.CHILD,
              value: "mobile"
          },
          range: {
              type: firebase.QueryRangeType.EQUAL_TO,
              value: mobile
          }
      }
  ))
  .do(firebaseResult => console.log('Checking for user success: ' + JSON.stringify(firebaseResult)))
  .filter(firebaseResult => firebaseResult.value != null);
}

public saveUser(user: User) {
  return Observable.defer(() => firebase.push('/users', user))
    .do(result => console.log(`created user with key ${result.key}`))
}