目前的主流浏览器都支持客户端缓存,用户在浏览网页的时候,浏览器会把网页里的文件数据缓存起来,当用户再次打开访问过的页面时,浏览器可以从本地缓存读取文件,减少网络下载文件等待的时间,同时也减轻了服务器的压力。总之浏览器文件缓存是个好东西,对用户好,对服务器好,对传输网络好;你好,我也好,大家好那是真的好。
有了浏览器的这个缓存,给开发者带来更多的发挥空间,不论是做后端程序开发,还是前端工程师,都离不开这块好地方。缓存管理的好坏,直接会影响到网站的用户体验。缓存做的好,占用的网络带宽小,服务器压力小,用户也感觉网站速度快,心情十分愉悦。缓存没控制好,每次都让用户多加载一些重复的文件,网页加载的时间变长,用户流失是必然的。
对于一些复杂的网页交互程序,比如网页游戏,往往需要的内容会比较多。如果优化的不好,自然要加载很多东西。如果一点一点的加载,用户操作几步就要等待一次网络加载,体验很不好。现在大部分这种复杂的应用,都会先让用户进入一段Loading动画,等需要的内容加载完毕,后面用户就可以很流畅的进行操作了。
目前使用Flash可以很容易的实现内容的预加载(Loading),对于非Flash的互联网产品,可以直接使用JavaScript来实现预加载。从目前网页交互应用程序来看,最占带宽的无非就是一些较大的图片文件、样式表文件和脚本文件,实现这些文件的预加载可以使用Iframe或者Image对象等来解决。
于是简单写了一个测试的小例子(查看效果),JavaScript代码:
var preloadFiles={ //debug模式 debug:false, //图片对象 imgLoader:null, //进度条 processBar:null, //初始化变量 initVars:function(){ //加载失败次数 this.errorCount=0; //待加载文件列表 this.filesList=[]; //待加载的文件总数 this.filesNumber=0; //当前正在加载的文件索引 this.currentFileIndex=0; //已经成功加载的文件 this.filesDownloadSuccess=[]; //预先加载结束 this.preloadFinished=false; }, //进度条 showProcessBar:function(){ if(this.processBar===null){ var barContainer=document.createElement('div'); barContainer.style.cssText='position:absolute; left:2px; top:2px; width:200px; height:6px; border:#9d9d9d 1px solid; padding:1px;'; this.processBar=document.createElement('div'); this.processBar.style.cssText='width:0%; height:6px; background-color:#33df33; font-size:6px;'; barContainer.appendChild(this.processBar); document.body.appendChild(barContainer); }else{ this.processBar.style.width=Math.ceil(((this.currentFileIndex-1)/this.filesNumber)*100).toString()+'%'; } }, //加载成功 loadSuccess:function(){ if(preloadFiles.debug){console.log('√ file "'+preloadFiles.filesList[preloadFiles.currentFileIndex-1]+'" load success!');} preloadFiles.filesDownloadSuccess.push(preloadFiles.filesList[preloadFiles.currentFileIndex-1]); preloadFiles.downloadElement(preloadFiles.filesList[preloadFiles.currentFileIndex++]); }, //加载失败 loadError:function(){ preloadFiles.errorCount++; if(preloadFiles.debug){console.error('× file "'+preloadFiles.filesList[preloadFiles.currentFileIndex-1]+'" load error!');} preloadFiles.downloadElement(preloadFiles.filesList[preloadFiles.currentFileIndex++]); }, //添加任务队列 addFileTasks:function(filesArray){ //把新的文件列表添加到任务队列 this.filesList=this.filesList.concat(filesArray); this.filesNumber=this.filesList.length; this.downloadElement(this.filesList[this.currentFileIndex++]); if(this.debug){ console.log('>>add '+filesArray.length+' files to task!'); console.log(this.filesList); } }, //load CSS loadCss:function(url){ var cssLoader=document.createElement('link'); cssLoader.setAttribute('href',url); cssLoader.setAttribute('type','text/css'); cssLoader.setAttribute('rel','stylesheet'); document.head.appendChild(cssLoader); }, //load Script loadScript:function(url){ var scriptLoader=document.createElement('script'); scriptLoader.setAttribute('src',url); scriptLoader.setAttribute('type','text/javascript'); scriptLoader.onload=this.loadSuccess; scriptLoader.onerror=this.loadError; document.body.appendChild(scriptLoader); }, //load Image loadImage:function(url){ if(this.imgLoader===null){ this.imgLoader=document.createElement('img'); this.imgLoader.setAttribute('src',url); this.imgLoader.setAttribute('width','0'); this.imgLoader.setAttribute('height','0'); document.body.appendChild(this.imgLoader); this.imgLoader.onload=this.loadSuccess; this.imgLoader.onerror=this.loadError; }else{ this.imgLoader.setAttribute('src',url); } }, //创建dom元素 downloadElement:function(url){ this.showProcessBar(); if(this.currentFileIndex>this.filesNumber){ setTimeout(function(){preloadFiles.processBar.parentNode.style.cssText='display:none;';},2000); this.preloadFinished=true; return false; } //匹配eg: xxx.css?version=n if(/\.(jpg|png|gif|bmp|jpeg|js|css)(\\?.+)?$/.test(url)){ if(this.debug){ //console.info('subfix=.'+RegExp.$1); console.log(' '); console.info('>>current is loading '+url+', ['+(this.currentFileIndex)+'/'+this.filesNumber+']'); } switch(RegExp.$1){ case 'css': this.loadCss(url); this.downloadElement(this.filesList[this.currentFileIndex++]); break; case 'js': this.loadScript(url); break; default: this.loadImage(url); break; } }else{ if(this.debug){ console.log(' '); console.warn(url+' is not a valid file, ['+(this.currentFileIndex)+'/'+this.filesNumber+']'); } this.downloadElement(this.filesList[this.currentFileIndex++]); } }, //初始化 initUrlArray:function(filesArray,urlPrefix){ for(var i=0,len=filesArray.length;i<len;i++){ if(!/^http:|https:/.test(filesArray[i])){ filesArray[i]=urlPrefix+filesArray[i]; } } return filesArray; }, //加载文件 load:function(filesArray,urlPrefix,debug){ if(filesArray&&filesArray.length&&filesArray.length>0){ if(filesArray.constructor!==Array){alert("参数错误,第一个参数需要为数组"); return false;} }else{ return; } if(urlPrefix){ if(urlPrefix===true){debug=urlPrefix; urlPrefix='';} if(urlPrefix.constructor!==String){alert("参数错误,第二个参数需要为字符串"); return false;} } this.debug=debug||false; //如果加载还未开始,或者已经加载结束,则重新初始化变量 if(!this.filesNumber||this.preloadFinished){this.initVars();} if(urlPrefix){ filesArray=this.initUrlArray(filesArray,urlPrefix); } //添加任务队列 this.addFileTasks(filesArray); } }
HTML代码部分:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>image_load_test</title>
</head>
<body>
<ul>
<li><input type="button" value="显示已缓存图片" /></li>
</ul>
<div id="test" class="display_none"></div>
<script type="text/javascript" src="index_v2.js"></script>
<script type="text/javascript">
//preloadFiles.load(ArrayFiles,UrlPrefix,debug);
preloadFiles.load([
'1.txt',
'2.jpg',
'http://www.baid.com/a.jpg',
'http://www.baidu.com/img/baidu_sylogo1.gif',
'http://localhost/demo_test/image_load_test/image_load_tes.js',
'http://www.google.com.hk/intl/zh-CN/images/logo_cn.png',
'http://www.baidu.com/img/baidu_sylogo1.gif'
],true);
preloadFiles.load(['3.txt','4.jpg'],'http://www.baidu.com/',true);
//display downloaded images
(function displayImages(){
var input=document.getElementsByTagName("input")[0];
input.onclick=function(){
if(!preloadFiles.preloadFinished){alert('图片加载中,请稍等!');return false;}
var url='';
var imagesList='';
for(var i=0,len=preloadFiles.filesDownloadSuccess.length;i<len;i++){
url=preloadFiles.filesDownloadSuccess[i];
if(/\.(jpg|gif|png|jpeg|bmp)$/.test(url)){
imagesList+='<li><img src="'+url+'" /></li>';
}
}
document.getElementsByTagName('ul')[0].innerHTML=imagesList;
//加载样式
preloadFiles.load(['image_load_test.css'],true);
}
})();
</script>
</body>
</html>
查看运行效果,如果使用Firefox/Chrome/IE8+,可以使用控制台查看加载状态。图片预加载完毕之后,断开网络,点击“显示已缓存图片”按钮,缓存图片会立即显示,而不需要请求网络。
画了一张浏览器文件缓存的分析图:
如果有兴趣,你还可以阅读以下文章:
http://www.fantxi.com/blog/archives/preload-images-css-js/
http://nootn.com/blog/Develop/44/

回复 (0)