一、发现黑科技的起因

 今天在微信公众号看到一篇技术博文,想用印象笔记收藏,所以发送了文章链接到pc上。然后习惯性地打开控制台,看看源码,想了解下最近微信用了什么新技术。

 呵呵,以下勾起了我侦探的欲望。页面加载后的异常点就是只加载了一个js,如下图所示:

 我很诧异,为什么已经开启了Disable cache,js只加载了一个,而且体积这么小。接着,我按住Ctrl+O进行资源文件查找,发现我被“忽悠”了。其实根本就不止一个js文件。

 脑袋里灵光一闪,不会是用localStorage做了缓存吧?!赶紧看了下localStronge,还真是。。。。

 心里一阵澎湃,这不是我之前就想实现的加载性能优化的想法吗!乖乖,我孤陋寡闻了,已经有前端团队实现了代码。

二、谈谈文件加载方面的优化思路

 通常,前端的资源文件加载优化,就是在文件不修改迭代的情况下,尽可能多地利用缓存,避免多次下载同样的文件。

 一般的做法就是尽量延长资源的有效期,也就是设置 Cache-Control里的max-age,使页面资源请求的返回码为304,让浏览器直接使用本地缓存。

 虽然pc端的协商缓存(304)很快,但手机端因为网络原因,协商缓存的效果就没pc端那么好了。而且,手机会经常清除本地缓存,所以文件缓存的时间也不会很长。

 这个时候,localStorage就派上用场了。

 localStorage相比cookie,可以缓存大体积的数据,而且是永久有效。所以,如果把js资源和css资源存储在localStorage中,则可以省去发送http请求所消耗的时间,大大提高用户的浏览体验。

三、用localStorage做资源缓存需要解决的问题

3.1 版本更新机制

 只要一个项目还在迭代开发,就难以避免需要更新资源文件。

 普通的资源请求,可以根据

 文件名+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做,则需要一套新的缓存更新机制。

3.2 搭建更新代码的脚手架

 使用localStorage缓存,则需要一个新的脚手架来管理资源文件的读取和写入。

3.3 后台输出一份资源配置信息

 因为需要前端做资源更新,所以后台要输出一份依据给前端做判断用,也就是需要一份资源配置信息。前端根据配置信息,进行匹配和比较,最终决定 使用localStorage缓存,还是重新发起请求,下载最新的资源文件。

3.4 存在XSS安全隐患

 localStorage中的信息,客户端是可以任意修改的。如果哪个黑客想练手一下,可以任意注入js代码。那么,在页面刷新的时候,注入的代码也将会被执行。

## 四、微信的做法解析

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

localStorage的黑科技-js和css缓存机制的更多相关文章

  1. 黑科技:纯CSS定制文本省略

    作者:weilong,腾讯 web前端开发 工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. WeTest导读 拿到设计MM的设计稿,Oh NO,点点点后面又双叒叕加内容了,弹丸 ...

  2. 解决前端js、css缓存问题

    去js标签库查询jquery.i18n.properties.js这个js引用到页面上: 新建一个配置文件:用上面的那个js方法调取配置文件里的版本号给其他的js加上: 示例: <script ...

  3. 关于更新发布CSS和JS文件的缓存问题

    现如今,浏览器大战下,各个浏览器也是拼了命的提高性能,升级JS解析引擎,更好的处理浏览器的页面缓存,让用户的浏览体验更快,占用更小的PC资源.那么,问题就出现在JS和CSS缓存,甚至页面缓存上.至于浏 ...

  4. [分享黑科技]纯js突破localstorage存储上线,远程抓取图片,并转码base64保存本地,最终实现整个网站所有静态资源离线到用户手机效果却不依赖浏览器的缓存机制,单页应用最新黑科技

    好久没有写博客了,想到2年前答应要放出源代码的也没放出来,最近终于有空先把纯js实现无限空间大小的本地存储的功能开源了,项目地址https://github.com/xueduany/localsto ...

  5. Cnblogs关于嵌入js和css的一些黑科技

    #pong .spoiler{cursor:none;display:inline-block;line-height:1.5;}sup{cursor:help;color:#3BA03B;} Pon ...

  6. JavaScript使用localStorage缓存Js和css文件

    对于WebApp来说,将js css文件缓存到localstorage区可以减少页面在加载时与HTTP请求的交互次数,从而优化页面的加载时间.特别是当移端信号不好高延迟时优化效果还是很显见的 下面的代 ...

  7. 探索前端黑科技——通过 png 图的 rgba 值缓存数据

    本文系原创,欢迎转载,转载请注明作者信息项目地址:SphinxJS在线体验地址:https://jrainlau.github.io/sp... 说起前端缓存,大部分人想到的无非是几个常规的方案,比如 ...

  8. 【半原创】将js和css文件装入localStorage加速程序执行

    首先感谢某某作者写的文章:http://www.jb51.net/article/12793.htm 直接上代码,注意文件名为env.js 原理如下: 一次批量加要加载的文件存入数组,采用Ajax方式 ...

  9. 将js和css文件装入localStorage加速程序执行

    原理如下: 一次批量加要加载的文件存入数组,采用Ajax方式异步载入各个文件,然后采用循环方式逐个执行下载下来的Js或者Css文件,如果已经被缓存(localStorage)的则省略下载过程. 由于J ...

随机推荐

  1. git 以及 github 使用系列

    本人打算开始写一个有关git 使用,以及github 使用的系列文章了,一来可以自己总结,二来github用好了,可以存放自己的一些知识框架吧. 1.准备 : 有一个 github上的账号, wind ...

  2. vi编辑器 :x与:wq的区别

    按一下ESC键,之后 :wq保存和退出VI [vi是Unix/Linux系统最常用的编辑器之一,我习惯使用":x"命令来保存文件并退出,不愿意使用":wq"命令 ...

  3. SqlServer拆分列

    SELECT TOP 1000 substring([a],0,CHARINDEX('/',a)) as low,substring([a],CHARINDEX('/',a)+1,len([a])-C ...

  4. CodeForces 609C Load Balancing

    先算出目标状态,然后拿当前状态与目标状态对比,即可算出答案 #include<cstdio> #include<cmath> #include<cstring> # ...

  5. git 与 github基本使用

    这里只对git 与 github的基本使用介绍,对于简单的步骤不做详细的说明,可以在网上搜索 一.git与github的安装与链接 1.git 安装:百度搜索"git",下载安装即 ...

  6. JavaScript(二)---- 变量、数据类型和运算符

    变量 javaScript中的变量变量是弱类型的,用var来声明. javascript的变量声明格式: var 变量名 = 数据; 声明变量要注意的事项: 1. 在javascript中声明变量是 ...

  7. jquery中:input和input的区别分析

    :input表示选择表单中的input,select,textarea,button元素,input仅仅选择input元素. <html> <head> <style&g ...

  8. OC语言的特性(一)-消息传递与调用函数的表现形式

    我们在初学Objective-C时,都会觉得ObjC中的消息传递和其他语言的调用函数差不多,只是在OC中,方法调用用消息传递这一概念来代替. 那么到底怎样区别OC中的消息传递与其他语言的调用函数呢. ...

  9. shell字符串操作之cut---实现字符串截取

    shell中(字符串截取) cut是以每一行为一个处理对象的,这种机制和sed是一样的.(关于sed的入门文章将在近期发布) 2 cut一般以什么为依据呢? 也就是说,我怎么告诉cut我想定位到的剪切 ...

  10. Android面试题随笔1

    1.如何让一个应用在手机上产生两个或多个图标? 在清单文件中的activity节点下配置如下:[5,7行代码] <activity android:name=".MainActivit ...