首页 > 解决方案 > 另一个(Angular)内部的两个或多个顺序请求

问题描述

我正在学习 rxjs,目前正试图弄清楚如何正确地发出一系列请求。例如,它的UserService一个方法通过用户 id 返回一个用户对象。比方说,在获得对象后,我想利用它包含的信息并发出一些帖子请求,如下所示:

    this.userService.getUser(5).subscribe(
      user => this.userService.sendEmail(this.makeEmailMessage(user.id, user.name, user.email)).pipe(
        delay(1000),
        tap(() => console.log('Sending an email'))
      ).subscribe(
        () => this.userService.sendSMS(this.makeSMSMessage(user.id, user.name, user.phone)).subscribe(
          () => console.log('Sending sms')
        )
      )
    );

但是它有很多嵌套的订阅,如果涉及到更多的请求,这些订阅可能会变得不可读和难以管理。

可以通过以下方式重写上面的代码:

    this.userService.getUser(5).pipe(
      switchMap(
        user => {
          return forkJoin(
            this.userService.sendEmail(this.makeEmailMessage(user.id, user.name, user.email)).pipe(
              delay(1000),
              tap(() => console.log('Sending a email.'))
            ),
            this.userService.sendSMS(this.makeSMSMessage(user.id, user.name, user.phone)).pipe(
              tap(() => console.log('Sending an sms'))
            )
          );
        }
      )
    ).subscribe(
      res => console.log(res)
    );

操作员保持请求的forkJoin顺序,但短信将首先完成。如果请求顺序无关紧要,那么我认为该代码可以,但是如果要求保持顺序怎么办。

无论如何,我想知道的是,当请求顺序很重要和不重要时,处理此类结构的最佳方法是什么。catchError另外,说到错误处理,我认为正确的方法是使用管道内的操作员(我使用的地方)来处理它tap。这是对的吗?

标签: angulartypescript

解决方案


如果电子邮件和 SMS 的顺序对您很重要,那么您可以使用switchMapoperator 对 HTTP 调用进行排序

   this.userService
      .getUser(5)
      // If error retrieving user, go straight to error block inside subscribe
      // no email, sms, push notification will be sent
      .pipe(
        switchMap(user => {
          return this.userService
            .sendEmail(this.makeEmailMessage(user.id, user.name, user.email))
            .pipe(
              // catchError((err, obs) => of({})) == if you wish to send SMS and Push notification even if sending email failed
              delay(1000),
              switchMap(() =>
                this.userService.sendSMS(
                  this.makeSMSMessage(user.id, user.name, user.phone)
                )
                // .pipe(catchError((error, obs) => of({})) if you wish to send Push notification even if sending SMS failed
              ),
              switchMap(() =>
                // Push Notification will occur last
                this.userService.sendPushNotification(
                  this.makePushNotificationMessage(
                    user.id,
                    user.name,
                    user.phone
                  )
                )
              )
            );
        })
      )
      .subscribe({
        next: next => {
          console.log(next);
        },
        error: error => {
          console.error(error);
        }
      });

通常,我们在使用运算符时应该非常小心,catchError()因为天真地使用它会抑制错误消息并使应用程序更难排除故障。catchError应该在内部将消息记录到控制台或某些记录系统,以便我们知道我们跳过了一个异常。


推荐阅读