利用Promise实现前端Ajax请求缓存与Token同步管理

作者:闭包旅人时间:2026-10-22 19:11:56浏览:311

本文介绍如何使用Promise实现简单的Ajax请求缓存,避免同一接口被重复发起。通过缓存请求对象而非结果值,确保多个组件共享最新Token,并在失败时自动刷新。方案涵盖七牛上传示例及配置加载场景,提供重试、错误处理等优化思路,无需引入额外缓存层即可提升前端性能与数据一致性。

业务场景与需求分析

业务场景

在许多实际业务中,我们需要对某些接口进行简单的请求缓存,确保特定请求仅被发起一次。典型的例子包括获取上传所需的Token或读取系统配置接口等。

利用Promise机制,我们可以直接对这些接口实现简单的缓存控制,并支持动态更新,从而避免引入额外的第三方缓存层。

基于Promise的Ajax缓存实现

示范代码

以七牛云存储上传为例,通常我们会将上传功能封装为一个独立的Upload组件。外部调用时只需触发组件,而Token的获取逻辑则封装在组件内部处理。


//Upload.vue
let fetchToken = null;
export default {
 data() {
  return {
   token: ''
  };
 },
 methods: {
  async upload() {
   try {
    // ...
   }
   catch(err) {
    alert(err.message);
    this.refreshToken();
   }
  },
  refreshToken() {
   fetchToken = null;
   this.fetchToken();
  },
  fetchToken() {
   if (!fetchToken) {
    fetchToken = request.get('/api/qiniu/token');
   }
   try {
    this.token = await fetchToken;
   }
   catch(err) {
    console.error(err);
   }
  }
 },
 created() {
  this.fetchToken();
 }
};

上述代码展示了缓存上传Token的基本实现,并在上传失败时具备刷新Token的机制。

缓存请求与缓存值的对比

与直接缓存Token数值相比,缓存整个请求对象有哪些优势?


// 缓存值的代码
export default {
 methods: {
  fetchToken() {
   if (!fetchToken) {
    fetchToken = await request.get('/api/qiniu/token');
   }
   try {
    this.token = fetchToken;
   }
   catch(err) {
    console.error(err);
   }
  }
 }
}

考虑一个常见的Upload组件应用场景:单个页面中同时存在多个该组件实例。


<template>
 <div class="upload1"><upload /></div>
 <div class="upload2"><upload /></div>
</template>

若采用直接缓存值的方法,如前文代码所示,页面加载时会触发两次获取Token接口的请求。

组件Token同步与优化策略

继续完善Upload组件逻辑


//Upload.vue
let fetchToken = null;
export default {
 methods: {
  async upload() {
   try {
    this.fetchToken();
    const token = await fetchToken;
    // ...
   } catch (err) {
    alert(err.message);
    this.refreshToken();
   }
  },
  refreshToken() {
   fetchToken = null;
   this.fetchToken();
  },
  fetchToken() {
   if (!fetchToken) {
    fetchToken = request.get('/api/qiniu/token');
   }
  }
 },
 created() {
  this.fetchToken();
 }
};

为避免多个Upload组件间Token不同步的问题,不再通过实例属性this.token保存Token,而是每次均等待fetchToken解析完成,确保获取到的Token始终是最新的。

当然,该方案仍有优化空间,例如增加失败重试机制、仅在401错误时刷新Token、设置错误时间戳或定时刷新等,但核心思路已在上述代码中体现。

配置加载场景应用

此外,再介绍一个经典应用场景


const fetchConfig = (() => {
 let configRequest = null;
 return () => {
  if (!configRequest) {
   configRequest = Promise.all([services.customer.config1, services.customer.config2])
    .then(([data1, data2]) => {
     return { data1, data2 };
    })
    .catch(err => {
     configRequest = null;
     return Promise.reject(err);
    });
  }
  return configRequest;
 };
})();

export default {
 async beforeRouteEnter(to, from, next) {
  try {
   // 配置信息仅需要成功请求一次
   const [data, config] = await Promise.all([services.customer.getInfo(), fetchConfig()]);
   next(vm => {
    vm.data = data;
    vm.config = config;
    vm.init();
   };
  } catch (err) {
   next(err);
  }
 }
};

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章