停止传播承诺(而不是拒绝它们)

问题描述 投票:0回答:1

我有一个带有“请求”方法的 HttpClient 类,负责向 API 发出请求并返回承诺,我从不同的服务调用此方法,在其中管理返回的承诺。

问题是,如果 HttpClient 收到会话过期错误,我会自动将用户从 HttpClient 重定向到登录页面,但由于始终从“request”方法返回承诺,因此调用 httpClient.request 的代码将继续执行并向用户显示小吃栏错误。

有没有办法确保一旦重定向到登录就不会执行任何其他操作? (请注意,由于它是 SPA(我使用 Vue 和 Nuxt.js),因此页面不会重新加载,因此代码执行不会中断。此外,如果我尝试使用 location.href 刷新整个页面,则会出现错误在页面刷新前一刻显示)

这个想法是不必管理每个服务中过期会话的被拒绝的承诺,因为我将在所有服务甚至调用服务的函数中重写相同的代码,因为许多服务也会返回一个承诺,所以我会必须一次又一次地兑现这些承诺。

我想必须有一些更好的方法来处理这个问题,但我不知道如何。

这是我当前的HttpClient请求方法实现(为了更好的理解进行了总结):

export default class HttpClient {
  [...]

  /**
  * Sends a request to the API and returns a promise with the result or an error.
  *
  * @param requestOptions
  * @return Promise
  */
  public async request(params) {
    [...]

    // Send request
    try {
      const response: ApiResponse = await $fetch(fetchUrl.toString(), requestOptions);

      if (this.hasError(response)) {
        const errorMessage = this.getErrorMessage(response as ErrorApiResponse);
        if (await this.checkSessionExpired(errorMessage)) return Promise.reject(new SessionExpiredError(errorMessage));
        return Promise.reject(new ApiHandledError(errorMessage));
      }

      return Promise.resolve(this.getData(response as SuccessApiResponse));
    } catch (error) {
      return Promise.reject(error);
    }
  }
}

我知道有几个与停止承诺传播相关的问题,但它们都没有回答我的问题,因为大多数答案都建议拒绝对我不起作用的承诺,因为这会在我的应用程序中向用户显示错误信息栏.

javascript promise software-design
1个回答
0
投票

只需将您的请求包装成承诺,不要解决它。

所有调用前分配的资源最终都会被释放,多测试几次,最终就会看到释放的情况。

class HttpClient {
  request(params) {
    return new Promise(async(resolve, reject) => {
      try{
        const response = await new Promise((resolve, reject) => {
          if(Math.random() > .33) {
            setTimeout(() => resolve(Math.random() > .5 ? {error:'session expired'} : {status: 'ok'}), 1000);
          }else{
            setTimeout(() => reject(new Error('Some api error has happenned')), 1000);
          }
        });
        if(response.error === 'session expired'){
          console.log('session expired, redirecting to login route'); 
          return;
        }
        resolve(response);
      }catch(e){
        reject(e);
      }
    });
  }
}

const http = new HttpClient;
const registry = new FinalizationRegistry(obj => {
  console.log(obj, ' released');
});
let callId = 1;
async function test(){
  try{
    const obj = {test: 'memory leak '.repeat(10000000)};
    console.log('memory:', Math.round(performance.memory.usedJSHeapSize/1024)+'Kb');
    registry.register(obj, 'test object ' + callId++);
    const response = await http.request();
    console.log('data received:', response);
  }catch(e){
    console.log('request error:', e.message);
  }
}
<button onclick="test()">test http request</button>
<div>it will give 3 random outcomes</div>

© www.soinside.com 2019 - 2024. All rights reserved.