100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Axios 如何缓存请求数据?

Axios 如何缓存请求数据?

时间:2018-11-13 17:38:03

相关推荐

Axios 如何缓存请求数据?

大家好,我是若川。欢迎加我微信ruochuan12,长期交流学习。今天推荐这篇Axios缓存请求数据的文章,相信是常见的业务场景,感兴趣的读者可以看看 umi-request,支持缓存功能。另外我之前也写过 axios源码文章,是转载次数(16次)最多的一篇文章,好久没写好文章了,惭愧惭愧。

点击下方卡片关注我,或者查看源码等系列文章。学习源码整体架构系列、年度总结、JS基础系列

在 Axios 如何取消重复请求? 这篇文章中,阿宝哥介绍了在 Axios 中如何取消重复请求及CancelToken的工作原理。本文将介绍在 Axios 中如何通过增强默认适配器来缓存请求数据。那么为什么要缓存请求数据呢?这是因为在缓存未失效时,我们可以直接使用已缓存的数据,而不需发起请求从服务端获取数据,这样不仅可以减少 HTTP 请求而且还能减少等待时间从而提高用户体验。

因为本文将使用 Axios 提供的默认适配器来实现缓存请求数据的功能,所以如果你对 Axios 适配器还不熟悉的话,建议先阅读 77.9K 的 Axios 项目有哪些值得借鉴的地方 这篇文章。为了让大家能够更好地理解后续的内容,我们先来看一下整体的流程图:

上图中蓝色部分的工作流程,就是本文的重点。接下来,阿宝哥将从如何设计缓存开始,带大家一起来开发缓存请求数据的功能。

一、如何设计缓存

在计算中,缓存是一个高速数据存储层,其中存储了数据子集,且通常是短暂性存储,这样日后再次请求该数据时,速度要比访问数据的主存储位置快。通过缓存,你可以高效地重用之前检索或计算的数据。了解完缓存的作用之后,我们来设计缓存的 API:

get(key):从缓存中获取指定key对应的值;

delete(key):从缓存中删除指定key对应的值;

clear():清空已缓存的数据;

set(key, value, maxAge):保存键值对,同时支持设置缓存的最大时间,即maxAge单位为毫秒。

基于上述的缓存 API,我们可以实现一个简单的缓存功能,具体代码如下所示:

constMemoryCache={data:{},set(key,value,maxAge){//保存数据this.data[key]={maxAge:maxAge||0,value,now:Date.now(),};},get(key){//从缓存中获取指定 key 对应的值。constcachedItem=this.data[key];if(!cachedItem)returnnull;constisExpired=Date.now()-cachedItem.now>cachedItem.maxAge;isExpired&&this.delete(key);returnisExpired?null:cachedItem.value;},delete(key){//从缓存中删除指定 key 对应的值。returndeletethis.data[key];},clear(){//清空已缓存的数据。this.data={};},};

其实除了自定义缓存对象之外,你也可以使用成熟的第三方库,比如 lru-cache。

LRU 缓存淘汰算法就是一种常用策略。LRU 的全称是 Least Recently Used,也就是说我们认为最近使用过的数据应该是是「有用的」,很久都没用过的数据应该是无用的,内存满了就优先删那些很久没用过的数据。

二、如何增强默认适配器

Axios 引入了适配器,使得它可以同时支持浏览器和 Node.js 环境。对于浏览器环境来说,它通过封装XMLHttpRequestAPI 来发送 HTTP 请求,而对于 Node.js 环境来说,它通过封装 Node.js 内置的httphttps模块来发送 HTTP 请求。

在介绍如何增强默认适配器之前,我们先来回顾一下 Axios 完整请求的流程:

了解完 Axios 完整请求的流程之后,我们再来看一下 Axios 内置的xhrAdapter适配器,它被定义在lib/adapters/xhr.js文件中:

//lib/adapters/xhr.jsmodule.exports=functionxhrAdapter(config){returnnewPromise(functiondispatchXhrRequest(resolve,reject){varrequestData=config.data;varrequestHeaders=config.headers;varrequest=newXMLHttpRequest();//省略大部分代码varfullPath=buildFullPath(config.baseURL,config.url);request.open(config.method.toUpperCase(),buildURL(fullPath,config.params,config.paramsSerializer),true);//SettherequesttimeoutinMSrequest.timeout=config.timeout;//Listenforreadystaterequest.onreadystatechange=functionhandleLoad(){...}//Sendtherequestrequest.send(requestData);});};

很明显xhrAdapter适配器是一个函数对象,它接收一个config参数并返回一个Promise对象。而在xhrAdapter适配器内部,最终会使用 XMLHttpRequest API 来发送 HTTP 请求。为了实现缓存请求数据的功能,我们就可以考虑通过高阶函数来增强xhrAdapter适配器的功能。

2.1 定义辅助函数

2.1.1 定义 generateReqKey 函数

在增强xhrAdapter适配器之前,我们先来定义一个generateReqKey函数,该函数用于根据当前请求的信息,生成请求 Key;

functiongenerateReqKey(config){const{method,url,params,data}=config;return[method,url,Qs.stringify(params),Qs.stringify(data)].join("&");}

通过generateReqKey函数生成的请求 key,将作为缓存项的 key,而对应的 value 就是默认xhrAdapter适配器返回的 Promise 对象。

2.1.2 定义 isCacheLike 函数

isCacheLike函数用于判断传入的 cache 参数是否实现了前面定义的 Cache API,利用该函数,我们允许用户为每个请求自定义 Cache 对象。

functionisCacheLike(cache){return!!(cache.set&&cache.get&&cache.delete&&cache.clear&&typeofcache.get==='function'&&typeofcache.set==='function'&&typeofcache.delete==='function'&&typeofcache.clear==='function');}

2.2 定义 cacheAdapterEnhancer 函数

为了让用户能够更灵活地控制数据缓存的功能,我们定义了一个cacheAdapterEnhancer函数,该函数支持两个参数:

adapter:预增强的 Axios 适配器对象;

options:缓存配置对象,该对象支持 4 个属性,分别用于配置不同的功能:

maxAge:全局设置缓存的最大时间;

enabledByDefault:是否启用缓存,默认为 true;

cacheFlag:缓存标志,用于配置请求 config 对象上的缓存属性;

defaultCache:用于设置使用的缓存对象。

了解完cacheAdapterEnhancer函数的参数之后,我们来看一下该函数的具体实现:

functioncacheAdapterEnhancer(adapter,options){const{maxAge,enabledByDefault=true,cacheFlag="cache",defaultCache=MemoryCache,}=options;return(config)=>{const{url,method,params,forceUpdate}=config;letuseCache=config[cacheFlag]!==undefined&&config[cacheFlag]!==null?config[cacheFlag]:enabledByDefault;if(method==="get"&&useCache){constcache=isCacheLike(useCache)?useCache:defaultCache;letrequestKey=generateReqKey(config);//生成请求KeyletresponsePromise=cache.get(requestKey);//从缓存中获取请求key对应的响应对象if(!responsePromise||forceUpdate){//缓存未命中/失效或强制更新时,则重新请求数据responsePromise=(async()=>{try{returnawaitadapter(config);//使用默认的xhrAdapter发送请求}catch(reason){cache.delete(requestKey);throwreason;}})();cache.set(requestKey,responsePromise,maxAge);//保存请求返回的响应对象returnresponsePromise;//返回已保存的响应对象}returnresponsePromise;}returnadapter(config);//使用默认的xhrAdapter发送请求};}

以上的代码并不会复杂,核心的处理逻辑如下图所示:

2.3 使用 cacheAdapterEnhancer 函数

2.3.1 创建 Axios 对象并配置 adapter 选项

consthttp=axios.create({baseURL:"",adapter:cacheAdapterEnhancer(axios.defaults.adapter,{enabledByDefault:false,//默认禁用缓存maxAge:5000,//缓存时间为5s}),});

2.3.2 使用 http 对象发送请求

//使用缓存asyncfunctionrequestWithCache(){constresponse=awaithttp.get("/todos/1",{cache:true});console.dir(response);}//不使用缓存asyncfunctionrequestWithoutCache(){constresponse=awaithttp.get("/todos/1",{cache:false});console.dir(response);}

其实 cache 属性除了支持布尔值之外,我们可以配置实现 Cache API 的缓存对象,具体的使用示例如下所示:

constcustomCache={get(){/*...*/},set(){/*...*/},delete(){/*...*/},clear(){/*...*/}};asyncfunctionrequestForceUpdate(){constresponse=awaithttp.get("/todos/1",{cache:customCache,forceUpdate:true,});console.dir(response);}

好了,如何通过增强xhrAdapter适配器来实现 Axios 缓存请求数据的功能已经介绍完了。由于完整的示例代码内容比较多,阿宝哥就不放具体的代码了。感兴趣的小伙伴,可以访问以下地址浏览示例代码。

完整的示例代码:/semlinker/b8a7bd5a0a16c2d04011c2c4a8167fbd

三、总结

本文介绍了在 Axios 中如何缓存请求数据及如何设计缓存对象,基于文中定义的cacheAdapterEnhancer函数,你可以轻松地扩展缓存的功能。在后续的文章中,阿宝哥将会介绍在 Axios 中如何实现请求重试功能,感兴趣的小伙伴不要错过哟。另外,如果你对 Axios 如何取消重复请求感兴趣,可以阅读 Axios 如何取消重复请求? 这篇文章。

四、参考资源

77.9K 的 Axios 项目有哪些值得借鉴的地方

Axios 如何取消重复请求?

Github - axios-extensions

最近组建了一个江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你进群。

·················若川出品·················

今日话题

建的江西前端交流群,感觉氛围不错,想着要不要建其他省份的交流群,不过我是江西人,建其他省份的会不会有人进群是个问题~。欢迎分享、收藏、点赞、在看我的公众号文章~

一个愿景是帮助5年内前端人走向前列的公众号

可加我个人微信 ruochuan12,长期交流学习

推荐阅读

我在阿里招前端,我该怎么帮你?(现在还能加我进模拟面试群)

如何拿下阿里巴巴 P6 的前端 Offer

点击方卡片关注我,或者查看源码等系列文章。

学习源码整体架构系列、年度总结、JS基础系列

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。