Skip to content

如何封装一个请求,让其多次调用的时候,实际只发起一个请求的时候,返回同一份结果?

封装一个请求使其在多次调用时只发起一次请求,并返回相同结果,通常是通过请求去重(debouncing)来实现的。这种功能对于避免重复的网络请求、提高性能和减少不必要的负载非常有用。

同时,我们需要确保在请求完成之前,对相同请求的重复调用都会共享相同的请求 Promise。避免出现连续发出相同的请求,在第一个请求尚未完成时,那么可能会发出多个请求的情况。

可以通过以下步骤来实现这个功能:

1. 使用一个缓存机制

我们可以使用 JavaScript 对象或 Map 来缓存已经发起的请求,并在 subsequent 请求中返回缓存的结果。缓存的关键是确保相同的请求参数对应同一个缓存条目。

2. 创建请求缓存封装

以下是一个基于 axios 的请求去重的封装示例:

javascript
import axios from 'axios';

// 请求缓存
const requestCache = new Map();

async function fetchData(url, params) {
  // 生成缓存 key
  const cacheKey = `${url}?${new URLSearchParams(params).toString()}`;

  // 检查缓存中是否已有数据
  if (requestCache.has(cacheKey)) {
    return requestCache.get(cacheKey);
  }

  // 创建请求 Promise
  const requestPromise = axios.get(url, { params })
    .then(response => {
      // 请求成功,存储结果
      requestCache.delete(cacheKey); // 请求完成后,移除缓存
      return response.data;
    })
    .catch(error => {
      // 请求失败,清除缓存
      requestCache.delete(cacheKey);
      throw error;
    });

  // 存储请求 Promise
  requestCache.set(cacheKey, requestPromise);

  // 返回 Promise
  return requestPromise;
}

export default fetchData;

注意事项:

  • 缓存请求 Promise:每个请求的 Promise 被缓存到 requestCache 中。后续的相同请求会返回这个缓存的 Promise。

  • 请求完成后移除缓存:请求成功或失败后,删除缓存,以防止缓存中的 Promise 长时间存在,避免内存泄漏。

  • 请求失败处理:如果请求失败,清理缓存并抛出错误,以便后续调用可以重新发起请求。

3. 使用请求缓存

使用封装好的 fetchData 函数来发起请求。多次调用相同的请求 URL 和参数只会发起一次网络请求,并返回相同的结果。

javascript
import fetchData from './fetchData';

// 使用示例
fetchData('https://api.example.com/data', { id: 1 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

// 再次调用相同的请求
fetchData('https://api.example.com/data', { id: 1 })
  .then(data => console.log(data)) // 共享相同的请求结果
  .catch(error => console.error(error));

题目要点:

  • 单一请求:确保相同请求的多次调用返回相同的 Promise,避免发出多个网络请求。
  • 缓存管理:请求完成后,删除缓存,避免长时间缓存未清理。
  • 错误处理:处理请求失败情况,并清理缓存以便重新请求。