const cacheMap = new Map();封装一下调用接口的方法,调用时先走咱们缓存数据。
import axios, { AxiosRequestConfig } from 'axios' // 堆代码 duidaima.com // 先来一个简简单单的发送 export function sendRequest(request: AxiosRequestConfig) { return axios(request) }然后加上咱们的缓存
import axios, { AxiosRequestConfig } from 'axios' import qs from 'qs' const cacheMap = new Map() interface MyRequestConfig extends AxiosRequestConfig { needCache?: boolean } // 这里用params是因为params是 GET 方式穿的参数,我们的缓存一般都是 GET 接口用的 function generateCacheKey(config: MyRequestConfig) { return config.url + '?' + qs.stringify(config.params) } export function sendRequest(request: MyRequestConfig) { const cacheKey = generateCacheKey(request) // 判断是否需要缓存,并且缓存池中有值时,返回缓存池中的值 if (request.needCache && cacheMap.has(cacheKey)) { return Promise.resolve(cacheMap.get(cacheKey)) } return axios(request).then((res) => { // 这里简单判断一下,200就算成功了,不管里面的data的code啥的了 if (res.status === 200) { cacheMap.set(cacheKey, res.data) } return res }) }然后调用
const getArticleList = (params: any) => sendRequest({ needCache: true, url: '/article/list', method: 'get', params }) getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) })这个部分就很简单,我们在调接口时给一个needCache的标记,然后调完接口如果成功的话,就会将数据放到cacheMap中去,下次再调用的话,就直接返回缓存中的数据。
getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) }) getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) })其实这样,就可以测出,我们的虽然设计了缓存,但是请求还是发送了两次,这是因为我们第二次请求发出时,第一次请求还没完成,也就没给缓存池里放数据,所以第二次请求没命中缓存,也就又发了一次。
// 堆代码 duidaima.com // 存储缓存当前状态,相当于挂牌子的地方 const statusMap = new Map<string, 'pending' | 'complete'>(); export function sendRequest(request: MyRequestConfig) { const cacheKey = generateCacheKey(request) // 判断是否需要缓存 if (request.needCache) { if (statusMap.has(cacheKey)) { const currentStatus = statusMap.get(cacheKey) // 判断当前的接口缓存状态,如果是 complete ,则代表缓存完成 if (currentStatus === 'complete') { return Promise.resolve(cacheMap.get(cacheKey)) } // 如果是 pending ,则代表正在请求中,这里就等个三秒,然后再来一次看看情况 if (currentStatus === 'pending') { return new Promise((resolve, reject) => { setTimeout(() => { sendRequest(request).then(resolve, reject) }, 3000) }) } } statusMap.set(cacheKey, 'pending') } return axios(request).then((res) => { // 这里简单判断一下,200就算成功了,不管里面的data的code啥的了 if (res.status === 200) { statusMap.set(cacheKey, 'complete') cacheMap.set(cacheKey, res) } return res }) }试试效果
getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) }) getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) })
成了!这里真的做到了,可以看到我们这里打印了两次,但是只发了一次请求。
// 定义一下回调的格式 interface RequestCallback { onSuccess: (data: any) => void onError: (error: any) => void } // 存放等待状态的请求回调 const callbackMap = new Map<string, RequestCallback[]>() export function sendRequest(request: MyRequestConfig) { const cacheKey = generateCacheKey(request) // 判断是否需要缓存 if (request.needCache) { if (statusMap.has(cacheKey)) { const currentStatus = statusMap.get(cacheKey) // 判断当前的接口缓存状态,如果是 complete ,则代表缓存完成 if (currentStatus === 'complete') { return Promise.resolve(cacheMap.get(cacheKey)) } // 如果是 pending ,则代表正在请求中,这里放入回调函数 if (currentStatus === 'pending') { return new Promise((resolve, reject) => { if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.push({ onSuccess: resolve, onError: reject }) } else { callbackMap.set(cacheKey, [ { onSuccess: resolve, onError: reject } ]) } }) } } statusMap.set(cacheKey, 'pending') } return axios(request).then( (res) => { // 这里简单判断一下,200就算成功了,不管里面的data的code啥的了 if (res.status === 200) { statusMap.set(cacheKey, 'complete') cacheMap.set(cacheKey, res) } else { // 不成功的情况下删掉 statusMap 中的状态,能让下次请求重新请求 statusMap.delete(cacheKey) } // 这里触发resolve的回调函数 if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.forEach((callback) => { callback.onSuccess(res) }) // 调用完成之后清掉,用不到了 callbackMap.delete(cacheKey) } return res }, (error) => { // 不成功的情况下删掉 statusMap 中的状态,能让下次请求重新请求 statusMap.delete(cacheKey) // 这里触发reject的回调函数 if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.forEach((callback) => { callback.onError(error) }) // 调用完成之后也清掉 callbackMap.delete(cacheKey) } // 这里要返回 Promise.reject(error),才能被catch捕捉到 return Promise.reject(error) } ) }在判断到当前请求状态是pending时,将promise的resole与reject放入回调队列中,等待被触发调用。然后在请求完成时,触发对应的请求队列。
getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) }) getArticleList({ page: 1, pageSize: 10 }).then((res) => { console.log(res) })
OK,完成了。
getArticleList({ page: 1, pageSize: 10 }).then( (res) => { console.log(res) }, (error) => { console.error(error) } ) getArticleList({ page: 1, pageSize: 10 }).then( (res) => { console.log(res) }, (error) => { console.error(error) } )
import axios, { AxiosRequestConfig } from 'axios' import qs from 'qs' // 存储缓存数据 const cacheMap = new Map() // 存储缓存当前状态 const statusMap = new Map<string, 'pending' | 'complete'>() // 定义一下回调的格式 interface RequestCallback { onSuccess: (data: any) => void onError: (error: any) => void } // 存放等待状态的请求回调 const callbackMap = new Map<string, RequestCallback[]>() interface MyRequestConfig extends AxiosRequestConfig { needCache?: boolean } // 这里用params是因为params是 GET 方式穿的参数,我们的缓存一般都是 GET 接口用的 function generateCacheKey(config: MyRequestConfig) { return config.url + '?' + qs.stringify(config.params) } export function sendRequest(request: MyRequestConfig) { const cacheKey = generateCacheKey(request) // 判断是否需要缓存 if (request.needCache) { if (statusMap.has(cacheKey)) { const currentStatus = statusMap.get(cacheKey) // 判断当前的接口缓存状态,如果是 complete ,则代表缓存完成 if (currentStatus === 'complete') { return Promise.resolve(cacheMap.get(cacheKey)) } // 如果是 pending ,则代表正在请求中,这里放入回调函数 if (currentStatus === 'pending') { return new Promise((resolve, reject) => { if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.push({ onSuccess: resolve, onError: reject }) } else { callbackMap.set(cacheKey, [ { onSuccess: resolve, onError: reject } ]) } }) } } statusMap.set(cacheKey, 'pending') } return axios(request).then( (res) => { // 这里简单判断一下,200就算成功了,不管里面的data的code啥的了 if (res.status === 200) { statusMap.set(cacheKey, 'complete') cacheMap.set(cacheKey, res) } else { // 不成功的情况下删掉 statusMap 中的状态,能让下次请求重新请求 statusMap.delete(cacheKey) } // 这里触发resolve的回调函数 if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.forEach((callback) => { callback.onSuccess(res) }) // 调用完成之后清掉,用不到了 callbackMap.delete(cacheKey) } return res }, (error) => { // 不成功的情况下删掉 statusMap 中的状态,能让下次请求重新请求 statusMap.delete(cacheKey) // 这里触发reject的回调函数 if (callbackMap.has(cacheKey)) { callbackMap.get(cacheKey)!.forEach((callback) => { callback.onError(error) }) // 调用完成之后也清掉 callbackMap.delete(cacheKey) } return Promise.reject(error) } ) } const getArticleList = (params: any) => sendRequest({ needCache: true, baseURL: 'http://localhost:8088', url: '/article/blogList', method: 'get', params }) export function testApi() { getArticleList({ page: 1, pageSize: 10 }).then( (res) => { console.log(res) }, (error) => { console.error('error1:', error) } ) getArticleList({ page: 1, pageSize: 10 }).then( (res) => { console.log(res) }, (error) => { console.error('error2:', error) } ) }最后