首先我们需要知道什么情况下浏览器会缓存下来文件,如下图所示:
上图为第一次我们打开云官网时,LCT-saas.js的请求情况,服务器返回200说明浏览器下载完成并成功,之后我们刷新网页
我们看到,服务器请求变成了304,为什么变成了304呢?事情要从两个小伙子说起,小伙子A我们称之为小浏(浏览器),小伙子B我们称之为小服(务器),第一次小浏拿到了这个js文件以后,在第二次打开网页的情况下,小浏问小服:你看看我请求你这个文件好像没什么变化呀,我需要更新吗?这时小服发现这个文件名称没有任何变化,大方的说:木有,继续拿去用吧,于是浏览器缓存出现了,何为缓存,即是说当浏览器再次访问服务器,而服务器处理发现没有变化时,允许使用本地已经下载好的文件处理继续浏览网页,该行为优化了网络请求,防止了无意义的带宽损耗。
我们知道了什么是缓存,那么问题就应运而生了,成也萧何败萧何,当浏览器方便了服务器时,给前端却带来了麻烦。
当有如下场景,一个图片不好看,我们要更换一个,会直接把原图片替换但是名称不变,又如在出现线上紧急bug,我们欣欣然改完了上线之后,会悲催的发现一件可怕的事情,为什么效果没有变,为啥bug还是存在,这就是浏览器缓存的可怕之处,而这是前端工程师必须面对的问题,怎么去处理本地缓存,怎么让用户清缓存,又如何自动的实现清缓存呢?
当我们还处在html1.0的时代,js还不足够强大,或者说性能还没有突飞猛进时,js作为脚本语言直接内嵌在html中已达到一些简单的效果,或者ajax局部刷新等功能,这个时代清除本地缓存的方式,显得原始而粗暴,例如php语言,我们会在上线前清除template_c中的缓存文件,已达到html模版文件为最新的目的,而由于js嵌入在html中,间接的达到了清除本地前端缓存的效果。
随着前端技术的发展,js性能越来越优越,业务逻辑开始像前端倾斜,前端的规范开始变得复杂,js受到重视,开始作为一种语言存在,我们开始使用script标签引入js文件,原始的方式是直接在html中写上js的文件路径即可,如下图:
这样的引入方式,直接导致缓存问题无法解决,于是,有聪明的人想到了地址随机数的方式,已后端语言java为例,在后端渲染的前提下,我们在模版语言jsp中写入一个version变量,之后再每一个js文件的src地址后面加入?vsrsion,如下图:
当我们刷新页面之后,发现js文件路径增加了?1.0.0成功去除了缓存,而这是过去js的通用操作方式,功能分文件,每个文件由一个自调用匿名函数包裹防止全局变量污染,上线修改version版本实现清除本地缓存功能。
当我们用到seajs(或者requirejs)时,由于是异步加载,我们不可避免的无法再使用过去写在html中的version来解决缓存问题,那么如何处理呢?
当我们去深层次的去剖析seajs的API参考文档时会出现一个有趣的配置map,官方解释为映射配置,什么又是映射呢?简单说就是两个事物相互对应,放到js中就变成了我可以通过方法修饰去指代同一个js地址(请注意这里需要区分alias别名的使用,这里不做介绍防止混乱),这里术语过多理解起来并没有实质性的功能,换一种对FE友好的说法:当我们加载jquery.js文件时,我们可以通过配置map,在这个地址中添加一串随机数,让这个文件保持最新而不去加载浏览器的缓存,发现没有?这就是自动清理掉缓存的方式!
首先我们下载seajs并写一个index.html,内容如下:
我们看到除了配置map,没有增加其他配置,注意map中的操作,其支持数组形式,在数组中允许使用正则和函数填充,当我们给map设置一个类似map函数返回新的地址时,“奇迹发生了”,如下图所示:
a.js后面增加了一串时间戳,这代表我们成功加载了这个js,之后我们不断刷新发现js并没有走浏览器的缓存,因为浏览器每次检测地址都是新的。
如上所示,现如今我们使用seajs(requirejs)来模块化我们的js文件,一个显示模块为一个文件,之后使用map映射的方式直接修改js异步加载地址来实现清理本地缓存的效果,之后合并压缩文件已达到上线标准。
前端发展迅速,之后涌现了如angularjs和reactjs这样的优秀框架,以他们为主导的前端工程化开发早已来临,而随着webpack的兴起,nodejs的完善,js可以做的事情已经越来越多了,我们能够想到一种可行的并且已经被部分公司使用的工作流是这样的,使用gulp编写node脚本,先使用webpack对js进行es6转义,之后非线上合并压缩用gulp的插件实现js合并压缩,通过自己写的node脚本使用fs模块读取html模版文件,插入合并完成的最终js文件,并且在脚本中写好md5或者时间戳即可实现本地缓存的清理。
创建三个简单的js文件,es6方式引入:
a.js文件
b.js文件
c.js文件
这之后我们编辑webpack配置文件,如下图:
这一步之前,我们使用cnpm安装babel-core和babel-preset-es2015模块,使用webpack执行该文件,可以看到a.js文件作为入口文件,最终被合成了main.js文件,实现了a、b、c三个文件的合并。
之后我们写一个脚本来实现给html注入js文件集,由于代码有些多,思路为字符串的替换,非常简单,顺便还做了html的压缩,核心代码如下:
读取html文件后替换即可,之后我们刷新页面可以看到:
这种方式不仅符合现在大部分潮流,实现了前端工程师高逼格的es6编程,而且使得js在本地就合并压缩不用代码处理,另外由于直接修改index.html文件,正式过去的实现方式,完美的解决了本地缓存问题。
我们之所以不懈的努力去实现自动清除本地缓存,是为了更好的用户体验已经,发生突发事件能够及时的响应,缓存一般会保留24小时,可以想象一个没有清理本地缓存能力的网站在遇到问题时将会是多么可怕的影响,本篇文章介绍了实现清理缓存的各个阶段的方式,希望对各位有所启发。