【半原创】将js和css文件装入localStorage加速程序执行
首先感谢某某作者写的文章:http://www.jb51.net/article/12793.htm
直接上代码,注意文件名为env.js
原理如下:
一次批量加要加载的文件存入数组,采用Ajax方式异步载入各个文件,然后采用循环方式逐个执行下载下来的Js或者Css文件,如果已经被缓存(localStorage)的则省略下载过程。
由于JS采用的是单线程模式运行,在执行某一个js时会阻塞其它并发的js执行,所以会按顺序执行各个js。在执行完所有的脚本之后,图片会被浏览器接着加载,所以第一次加载速度略慢,后面就会比较快了。在JQuery Mobile 1.4.5+FireFox/微信浏览器下实测效果不错,IE就被省略了,我主要是要在微信浏览器下使用。
//需要引用别的js的时候,就加上如Env.require("cookie.js"),或Env.require("/common/cookie.js"),是用相对路径还是绝对路径就看喜好了。
//Env.require可用在页面模板中,也可用在js文件中,但一定要保证执行时env.js被显式引入。
//多次Env.require同一个js(不管用相对还是绝对),只有第一次会加载,所以不会重复。
//程序最后发行的版本,用于作为缓存键的前缀,快速更新缓存
var envLastVer = '2014_11_17_17_03';
//用于存放通道名称及通信对象的类,这样可以通过不同通道名称来区分不同的通信对象
function HttpRequestObject() {
this.chunnel = null;
this.instance = null;
}
//用于获取的脚本或css文件保存对象
function HttpGetObject() {
this.url = null; //要下载的文件路径
this.cache_key = null; //缓存键
this.chunnel = null; //通道名
this.type = null; //类型,js或css
this.is_fill = false; //内容是否被填充
this.is_exec = false; //内容是否已被执行,防止分几大块载入后重复执行
}
//通信处理类,可以静态引用其中的方法
var Request = new function () {
//通信类的缓存
this.httpRequestCache = new Array();
//创建新的通信对象
this.createInstance = function () {
var instance = null;
if (window.XMLHttpRequest) {
//mozilla
instance = new XMLHttpRequest();
//有些版本的Mozilla浏览器处理服务器返回的未包含XML mime-type头部信息的内容时会出错。
//因此,要确保返回的内容包含text/xml信息
if (instance.overrideMimeType) {
instance.overrideMimeType = "text/xml";
}
}
else if (window.ActiveXObject) {
//IE
var MSXML = ['MSXML2.XMLHTTP.5.0', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
for (var i = 0; i < MSXML.length; i++) {
try {
instance = new ActiveXObject(MSXML[i]);
break;
}
catch (e) {
}
}
}
return instance;
}
/**
* 获取一个通信对象
* 若没指定通道名称,则默认通道名为"default"
* 若缓存中不存在需要的通信类,则创建一个,同时放入通信类缓存中
* @param _chunnel:通道名称,若不存在此参数,则默认为"default"
* @return 一个通信对象,其存放于通信类缓存中
*/
this.getInstance = function (_chunnel) {
var instance = null;
var object = null;
if (_chunnel == undefined)//没指定通道名称
{
_chunnel = "default";
}
var getOne = false;
for (var i = 0; i < this.httpRequestCache; i++) {
object = HttpRequestObject(this.httpRequestCache[i]);
if (object.chunnel == _chunnel) {
if (object.instance.readyState == 0 || object.instance.readyState == 4) {
instance = object.instance;
}
getOne = true;
break;
}
}
if (!getOne) //对象不在缓存中,则创建
{
object = new HttpRequestObject();
object.chunnel = _chunnel;
object.instance = this.createInstance();
this.httpRequestCache.push(object);
instance = object.instance;
}
return instance;
}
/**
* 客户端向服务端发送请求
* @param _url:请求目的
* @param _data:要发送的数据
* @param _processRequest:用于处理返回结果的函数,其定义可以在别的地方,需要有一个参数,即要处理的通信对象
* @param _chunnel:通道名称,默认为"default"
* @param _asynchronous:是否异步处理,默认为true,即异步处理
* @param _paraObj:相关的参数对象
*/
this.send = function (_url, _data, _processRequest, _chunnel, _asynchronous, _paraObj) {
if (_url.length == 0 || _url.indexOf("?") == 0) {
alert("由于目的为空,请求失败,请检查!");
return;
}
if (_chunnel == undefined || _chunnel == "") {
_chunnel = "default";
}
if (_asynchronous == undefined) {
_asynchronous = true;
}
var instance = this.getInstance(_chunnel);
if (instance == null) {
alert("浏览器不支持ajax,请检查!")
return;
}
if (_asynchronous == true && typeof (_processRequest) == "function") {
instance.onreadystatechange = function () {
if (instance.readyState == 4) // 判断对象状态
{
if (instance.status == 200) // 信息已经成功返回,开始处理信息
{
_processRequest(instance, _paraObj);
}
else {
alert("您所请求的页面有异常,请检查!");
}
}
}
}
//_url加一个时刻改变的参数,防止由于被浏览器缓存后同样的请求不向服务器发送请求
if (_url.indexOf("?") != -1) {
_url += "&requestTime=" + (new Date()).getTime();
}
else {
_url += "?requestTime=" + (new Date()).getTime();
}
if (_data.length == 0) {
instance.open("GET", _url, _asynchronous);
instance.send(null);
}
else {
instance.open("POST", _url, _asynchronous);
instance.setRequestHeader("Content-Length", _data.length);
instance.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
instance.send(_data);
}
if (_asynchronous == false && typeof (_processRequest) == "function") {
_processRequest(instance, _paraObj);
}
}
}
var Env = new function () {
this.needLoadObject = new Array();
//获取env.js文件所在路径
this.envPath = null;
this.getPath = function () {
this.envPath = document.location.pathname;
this.envPath = this.envPath.substring(0, this.envPath.lastIndexOf("/") + 1);
var _scripts = document.getElementsByTagName("script");
var _envPath = null;
var _scriptSrc = null;
for (var i = 0; i < _scripts.length; i++) {
_scriptSrc = _scripts[i].getAttribute("src");
if (_scriptSrc && _scriptSrc.indexOf("env.js") != -1) {
break;
}
}
if (_scriptSrc != null) {
if (_scriptSrc.charAt(0) == '/') {
this.envPath = _scriptSrc.substr(0, _scriptSrc.length - 6);
}
else {
this.envPath = this.envPath + _scriptSrc.substr(0, _scriptSrc.length - 6);
}
}
}
this.getPath();
//获取文件后缀名
this.getFileExt = function (fileUrl) {
var d = /\.[^\.]+$/.exec(fileUrl);
return d.toString().toLowerCase();
}
//依次放入要载入的文件
this.pushNeedLoad = function (url) {
var _absUrl = null;
if (url.charAt(0) == '/')
_absUrl = url;
else
_absUrl = this.envPath + url;
var object = new HttpGetObject();
object.url = _absUrl;
object.cache_key = envLastVer + _absUrl; //利用版本号+绝对路径生成缓存键
object.chunnel = 'ch' + (this.needLoadObject.length + 1);
object.type = this.getFileExt(_absUrl);
//尝试从缓存获取
var cacheContent = localStorage.getItem(object.cache_key);
if (cacheContent) { object.is_fill = true; }
this.needLoadObject.push(object);
return this;
}
//依次装载要处理的文件
this.batchLoad = function () {
for (var i = 0; i < this.needLoadObject.length; i++) {
var item = this.needLoadObject[i];
var processGet = function (_instance, _paraObj) {
localStorage.setItem(_paraObj.cache_key, _instance.responseText); //缓存文件
_paraObj.is_fill = true;
}
if (item.is_fill == false) {
Request.send(item.url, "", processGet, item.chunnel, false, item); //采用同步方式载入
}
}
return this;
}
//依次执行要处理的文件
this.batchExec = function () {
var runCss = function (_css) { document.write('<style type="text/css">' + _css + '</style>'); }
var runJs = function (_js) {
if (window.execScript)
window.execScript(_js);
else
window.eval(_js);
}
//依次执行,由于js为单线程执行,每执行一个js都会阻塞其它,所以可以保证顺序执行
for (var i = 0; i < this.needLoadObject.length; i++) {
var item = this.needLoadObject[i];
if (item.is_exec == false) {
if (item.type == '.js') {
runJs(localStorage.getItem(item.cache_key));
item.is_exec = true; //标记已执行,下次不会再执行
}
else if (item.type == '.css') {
runCss(localStorage.getItem(item.cache_key));
item.is_exec = true; //标记已执行,下次不会再执行
}
}
}
}
}
下面是调用方法:
Env.pushNeedLoad("jquery.mobile-1.4.5/jquery.min.js")
.pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.css")
.pushNeedLoad("/plus_in/weixin/procedure/scripts/task.util.js")
.pushNeedLoad("/plus_in/weixin/procedure/scripts/emcp.mobile.js")
.pushNeedLoad("/plus_in/weixin/procedure/scripts/common.index.js")
.pushNeedLoad("jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.js")
.pushNeedLoad("mobiscroll.2.6/css/mobiscroll.custom-2.6.2.min.css")
.pushNeedLoad("mobiscroll.2.6/js/mobiscroll.custom-2.6.2.min.js")
.pushNeedLoad("/plus_in/weixin/procedure/style/base.css")
.batchLoad().batchExec();
通过火狐F12观察,发现上面的脚本第一次会被加载,后面将会直接从localstorage中读取,节省了很多,将js用于微信浏览器后,也节省了很多带宽。不过第一次加载还是有些慢的,毕竟还是有那么多数据。
【半原创】将js和css文件装入localStorage加速程序执行的更多相关文章
- 将js和css文件装入localStorage加速程序执行
原理如下: 一次批量加要加载的文件存入数组,采用Ajax方式异步载入各个文件,然后采用循环方式逐个执行下载下来的Js或者Css文件,如果已经被缓存(localStorage)的则省略下载过程. 由于J ...
- 常用js,css文件统一加载方法,并在加载之后调用回调函数
原创内容,转载请注明出处! 为了方便资源管理和提升工作效率,常用的js和css文件的加载应该放在一个统一文件里面完成,也方便后续的资源维护.所以我用js写了以下方法,存放在“sourceControl ...
- js或css文件后面的参数是什么意思?
经常看到不少导航网站测样式或js文件后面加了一些参数,主要是一你为一些并不经常更新的页面重新加载新修改的文件. 经常遇到页面里加载的js与css文件带有参数,比如: <script type=& ...
- MVC学习随笔----如何在页面中添加JS和CSS文件
http://blog.csdn.net/xxjoy_777/article/details/39050011 1.如何在页面中添加Js和CSS文件. 我们只需要在模板页中添加JS和CSS文件,然后子 ...
- grunt 单独压缩多个js和css文件【转】
原文地址:http://xiaomiya.iteye.com/blog/2177877 使用grunt来压缩前端js,css文件 因为最近做的客户端本地项目有用到十几个js,js提交之前都需要压缩.用 ...
- gulp-rev同时将js和css文件写在一个rev-manifest.json文件里面的方式探讨
参考: https://segmentfault.com/q/1010000002876613 https://github.com/sindresorhus/gulp-rev 测试发现,在官网上最主 ...
- 使用Maven构建Java Web项目时,关于jsp中引入js、css文件路径问题。
今天有点闲,自己动手搭建一个Java Web项目,遇到jsp中引入js.css文件时路径不正确的问题,于是在网上查阅了很多资料,最终都无法解决问题,于是,上stackoverflow找到了解决方法,这 ...
- [转][前端优化]使用Combres合并对js、css文件的请求
本文转自:http://www.cnblogs.com/parry/archive/2011/01/28/Reduce_Http_Request_Using_Combres_For_Js_Css.ht ...
- 为js和css文件自动添加版本号
web应用必然要面对缓存问题,无论前台后台都会涉足缓存.特别是对于前端而言,缓存利用的是否得当直接关系到应用的性能. 通常情况下,我们会倾向于使用缓存,因为缓存一方面可以减少网络开销,一方面可以减轻服 ...
随机推荐
- [Swift系列]002-基础语法
基础语法就那老几样,很快可以说完 [常量.变量] 1.变量用 var,系统自动去判断类型,但变量再次赋值需保持数据类型一致 var a=50 相信用过js/java/C#的,对这个var都不陌生 使 ...
- linux vim 配置文件(高亮+自动缩进+行号+折叠+优化)
点评:将一下代码copy到 用户目录下 新建文件为 .vimrc保存即可生效 如果想所有用户生效 请修改 /etc/vimrc (建议先cp一份)"===================== ...
- python练习程序(c100经典例14)
题目: 将一个正整数分解质因数.例如:输入90,打印出90=2*3*3*5. def foo(n): while 1: for i in range(2,n+1): if n%i==0: print ...
- struts2运行机制
struts2是web应用中一个常用的mvc框架,下面探讨一下其内部运行机制: 1.从客服端浏览器输入的url后,客服端通过http协议发送一个请求到服务器(tomcat),Tomcat收到这个请求之 ...
- Mysql 不同版本 说明
Mysql 的官网下载地址: http://dev.mysql.com/downloads/ 在这个下载界面会有几个版本的选择. 1. MySQL Community Server 社区版本,免费,但 ...
- java web项目导入问题
由于工作问题,接触到很多其他人的项目,有时候想要直接跑起来,还是需要一定的耐力. 1:导入不进去,干脆新建项目,一个个复制进去: 2:第三方jar包不要忘记,核实jdk j2ee的版本,编译路径 ...
- app如何节省流量
前言:“客户端上传时间戳”的玩法,你玩过么?一起聊聊时间戳的奇技淫巧! 缘起:无线时代,流量敏感.APP在登录后,往往要向服务器同步非常多的数据,很费流量,技术上有没有节省流量的方法呢?这是本文要讨论 ...
- python+selenium环境搭建
这里主要基于windows平台. 下载python.http://python.org/getit/ 下载setuptools [python的基础包工具].http://pypi.python.or ...
- 部署WAR文件到tomcat
1.启动tomcat服务 2.在浏览器的地址栏输入地址“http://localhost:8080/manager/html”进入tomcat管理界面. 如果要管理的服务器是在网络中,则将localh ...
- 面积最大的全1子矩阵--九度OJ 1497
题目描述: 在一个M * N的矩阵中,所有的元素只有0和1,从这个矩阵中找出一个面积最大的全1子矩阵,所谓最大是指元素1的个数最多. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行是 ...