今天在微信公众号看到一篇技术博文,想用印象笔记收藏,因此发送了文章连接到pc上。而后习惯性地打开控制台,看看源码,想了解下最近微信用了什么新技术。
呵呵,如下勾起了我侦探的欲望。页面加载后的异常点就是只加载了一个js,以下图所示:css
我很诧异,为何已经开启了Disable cache,js只加载了一个,并且体积这么小。接着,我按住Ctrl+O进行资源文件查找,发现我被“忽悠”了。其实根本就不止一个js文件。html
脑壳里灵光一闪,不会是用localStorage作了缓存吧?!赶忙看了下localStronge,还真是。。。。前端
内心一阵澎湃,这不是我以前就想实现的加载性能优化的想法吗!乖乖,我孤陋寡闻了,已经有前端团队实现了代码。git
一般,前端的资源文件加载优化,就是在文件不修改迭代的状况下,尽量多地利用缓存,避免屡次下载一样的文件。
通常的作法就是尽可能延长资源的有效期,也就是设置 Cache-Control里的max-age,使页面资源请求的返回码为304,让浏览器直接使用本地缓存。
虽然pc端的协商缓存(304)很快,但手机端由于网络缘由,协商缓存的效果就没pc端那么好了。并且,手机会常常清除本地缓存,因此文件缓存的时间也不会很长。
这个时候,localStorage就派上用场了。
localStorage相比cookie,能够缓存大致积的数据,并且是永久有效。因此,若是把js资源和css资源存储在localStorage中,则能够省去发送http请求所消耗的时间,大大提升用户的浏览体验。github
3.1 版本更新机制web
只要一个项目还在迭代开发,就难以免须要更新资源文件。
普通的资源请求,能够根据
文件名+md5 http://res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/biz_wap/moon32ebc4.js
或者
在资源连接后面加上特定的后缀http://1.ss.faisys.com/js/comm/fai.min.js?v=201612051739
作标识来判断是否须要更新资源。
若是用localStorage作,则须要一套新的缓存更新机制。json
3.2 搭建更新代码的脚手架浏览器
使用localStorage缓存,则须要一个新的脚手架来管理资源文件的读取和写入。缓存
3.3 后台输出一份资源配置信息安全
由于须要前端作资源更新,因此后台要输出一份依据给前端作判断用,也就是须要一份资源配置信息。前端根据配置信息,进行匹配和比较,最终决定 使用localStorage缓存,仍是从新发起请求,下载最新的资源文件。
3.4 存在XSS安全隐患
localStorage中的信息,客户端是能够任意修改的。若是哪一个黑客想练手一下,能够任意注入js代码。那么,在页面刷新的时候,注入的代码也将会被执行。
## 4、微信的作法解析
4.1 版本标识
以__MOON__a/a_report.js
为例,版本信息用key __MOON__a/a_report.js_ver
存储,存储的value为//res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/a/a_report32e586.js
。
若是按普通加载方式,直接将该value取出来,设置到script节点的src属性,便可完成加载。
微信判断该版本是否最新,就是用该value值与后台输出的配置信息进行比较,最后得出是否更新的结果。
若是value值与配置信息一致,则使用缓存。不然,从新发起请求加载。
4.2 脚手架
能够看出,微信使用的是本身开发的脚手架moon.js,在这个网页中的实际文件名是moon32ebc4.js
。
由于是混淆过变量名的文件,因此要看出具体代码的走向,有点费劲,这里就不作分析了。
4.3 资源配置信息
由于脚手架moon.js须要资源配置信息才能正常工做,因此配置信息必定会在moon.js以前输出。
依次查看moon.js以前的script标签,发现了window.moon_map
这个json对象。
利用控制台输出该变量查看信息以下:
看到这里,能够明确一个点:这就是更新机制所必备的资源配置信息表了。
并且,能够看出,该配置信息json对象的key,就对应localStorage中的key。同理,value值也是一一对应。
4.4 XSS攻击
此处是为了验证微信的缓存机制是否存在XSS攻击,看到这里的童鞋可千万不要去作坏事。
我在一个js缓存代码中,插入alert("hehe");
,看页面刷新的时候,是否会出现该弹窗,来验证是否存在攻击漏洞。
刷新页面后,结果以下图:
能够看出,微信也没有解决这类问题。因此,这种缓存机制,仍是有先天不足的。
4.5 测试微信的更新机制
修改localStorage中 key __MOON__a/a_report.js_ver
对应的value值,让微信的脚手架moon.js更新__MOON__a/a_report.js
,刷掉我刚才主动插入的代码。
这里,我修改文件名为***587.js
(原来的文件名为***586.js
)。接着F5刷新页面。
结果为:report.js代码更新了,版本号也恢复回 ***586.js
。
localStorage缓存有其用武之地,但不是万能的。须要注意以上说起的坑。
能够应用的场景我概括为如下几点:
1. 非首屏渲染须要的css文件,能够作LS缓存。
首屏渲染须要的css,须要按常规方式输出,由于SEO须要,否则爬虫爬取页面的时候,页面效果会很很差。而非首屏的css,则能够用LS缓存,减小资源下载时间。
2. 展现类、动画类等非业务主要逻辑的代码,能够作LS缓存。
这样,能够必定程度上避免业务层的安全漏洞。固然,前端再怎么作防御都是一层薄纸。重要的,仍是后台接口要作好安全保护。
3. 移动端能够作LS缓存。PC端作LS缓存,起到的优化做用不大。
有兴趣的童鞋,还能够看看知乎上大神们的讨论,静态资源(JS/CSS)存储在localStorage有什么缺点?为何没有被普遍应用? - 互联网 - 知乎
另外,腾讯网的前端,在gitHub上有分享其MT 模块管理框架,能够看看具体的实现逻辑。
最后,上一个栗子 —— 线上实例demo:webapp模块化开发体系
简书入口:www.jianshu.com/p/0fa0bf842bbb