【问题标题】:Awaiting the value of a promise without using the async await keywords?在不使用 async await 关键字的情况下等待 promise 的值?
【发布时间】:2020-02-06 16:57:14
【问题描述】:

在我的 Angular HttpInterceptor 类中,我正在实现一种刷新机制,用于检测 JWT 令牌何时过期,并从后端检索一个新令牌。一旦检索到新的令牌,它将覆盖本地存储中的令牌,从而延长用户会话的到期时间。

HttpInterceptor 的部分功能是在检测到 JWT 到期日期已到时让用户退出会话。

但是我遇到了一个问题。发出 JWT 请求后,似乎马上又向后端发送了另一个请求。由于此时令牌已过期,API 将返回 403,并且拦截器正在检测到这一点,并在返回带有新 JWT 令牌的响应之前将用户踢出会话。这意味着用户在令牌有机会刷新之前被注销。

通常这不是问题,因为我可以使用 async/await 来确保在发出任何其他请求之前返回新的 JWT。但是,这在拦截器中不起作用,因为它实现了HttpInterceptor 接口,这意味着如果我尝试在接口实现的intercept 方法上使用async 关键字,那么我会得到一个编译器错误作为返回intercept方法的类型必须是Observable<HttpEvent<T>>,不能是Promise<Observable<HttpEvent<T>>>

//The below violates the HttpInterceptor interface
async intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Promise<Observable<HttpEvent<any>>> { ... }

//The below violates the async keyword
async intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> { ... }

我当前的拦截方法代码如下。

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = this.addHeaders(req);

    if(req.headers.has("refreshTokenRequest")) {
      return next.handle(req).pipe(tap(val => console.log("Interceptor handler, req to: " + req.url)));
    }

    if(localStorage.getItem("jwt_token")) {
      if(util.isJwtExpired("jwt_token")) {
        console.log("Jwt is expired, getting new token");
        this.getNewToken().then(newTokenResponse => {  //the .then() method needs to be awaited so that the expired JWT token can be overwritten before ANY other requests are sent
          this._authService.setAuthorizationToken(newTokenResponse.token);
          console.log("New token set");
          return this.handleRequestWithCatchError(req, next);
        });

      }
    }

    return this.handleRequestWithCatchError(req, next);
  }

因此,我需要一种方法来等待 this.getNewToken() 承诺的返回值,而无需使用 async/await 关键字。有没有办法做到这一点?

【问题讨论】:

    标签: javascript angular promise async-await


    【解决方案1】:

    你不应该使用 Promise,而应该使用 observables。

    无论如何,只需将它包装在您在加载数据时解决的承诺中。

    req = this.addHeaders(req);
    const prom = new Promise((resolve, reject) => {
      if(req.headers.has("refreshTokenRequest")) {
      // Your code here
      }
    })
    
    return prom.then(v => this.handleRequestWithCatchError(req, next));
    

    编辑

    正如@mbojko 指出的那样,返回一个可观察对象(就像我首先说的那样),因为the signature 不接受承诺。

    return from(prom.then(v => this.handleRequestWithCatchError(req, next)));
    

    【讨论】:

    • 在拦截方法中?这将是相同的 TS 错误。
    • intercept 应该返回一个可观察的,你返回一个承诺。
    • @mbojko 哦,好吧,没注意,抱歉!马上解决。
    • @mbojko(TBH 我只是根据他的代码来回答我的问题,假设它正在工作。将编辑添加到我的回答中)
    【解决方案2】:

    你可以从promise创建一个observable,并使用mergeMap操作符来合并你想要返回的observable。

    
      import { from } from 'rxjs';
      import { tap, mergeMap } from 'rxjs/operators';
    
      ...
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        req = this.addHeaders(req);
    
        if(req.headers.has("refreshTokenRequest")) {
          return next.handle(req).pipe(tap(val => console.log("Interceptor handler, req to: " + req.url)));
        }
    
        if(localStorage.getItem("jwt_token")) {
          if(util.isJwtExpired("jwt_token")) {
            console.log("Jwt is expired, getting new token");
            return from(this.getNewToken.call(this)).pipe(
              tap(newTokenResponse => {
                this._authService.setAuthorizationToken(newTokenResponse.token)
              }),
              mergeMap(() => this.handleRequestWithCatchError(req, next))
            )
    
          }
        }
        return this.handleRequestWithCatchError(req, next);
      }
    

    【讨论】:

    • 你能解释一下为什么在这种情况下我会使用 mergemap 而不是 concatMap 吗?我原以为我想要 concatMap 以便我可以确保观察到的顺序得到维护?
    • 也可以解释一下.call(this)这一行this.getNewToken.call(this))
    • @Jake12342134 在这种情况下没有区别,因为operator内部只有一次observable
    • 我不确定您的getNewToken 方法中是否使用了this 关键字,所以我给出了this 值。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • 不是有两个吗?第一个由fromPromise(this.getNewToken()) 创建,第二个由this.handleRequestWithCatchError(req, next) 返回,它返回Observable&lt;HttpEvent&lt;Any&gt;&gt;?
    猜你喜欢
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 2016-03-08
    • 2021-04-05
    • 1970-01-01
    • 2022-11-07
    • 1970-01-01
    相关资源
    最近更新 更多