社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
包括:资源的合并与压缩,图片编码原理和类型选择,浏览器的渲染机制,懒加载预加载,浏览器存储,缓存机制,PWA,Vue-SSR等页面优化的功能。
1.基础优化:
1.1 资源的合并与压缩:
1.1.1 理解减少http请求和减少请求资源大小的优化:包括html压缩,css压缩,js压缩,文件合并,开启gzip。
① html压缩:包括空格,制表符,换行符等,以及HTML注释都可以被压缩。一般一个24KB的html文件压缩之后,是22-23KB大小,看是html压缩不大,但是以谷歌来说,如果1KB(即1024b字节)经过HTML压缩减少一个字节,那么每年也能替谷歌节约500TB流量,约近亿元的节约量。
如何进行html压缩?:包括在线网站压缩(如http://tool.oschina.net),nodejs提供了html-minfier工具,后端模块引擎渲染压缩。目前很多框架的构建工具,如vue-cli,webpack等都已经在打包项目代码的时候进行了html压缩。
② css压缩:包括删除无效css代码,如注释,合并相同css代码等。
如何进行css压缩?:包括在线网站压缩(如http://tool.oschina.net),nodejs提供了html-minfier工具,使用clean-css对css进行压缩。目前很多框架的构建工具,如vue-cli,webpack等都已经在打包项目代码的时候进行了css压缩。
③ js压缩:包括删除无效代码/字符,剔除注释,代码语义的缩减和优化,代码保护(让人不容易一眼看清晰代码)。
如何进行js压缩?:包括在线网站压缩(如http://tool.oschina.net),nodejs提供了html-minfier工具,使用uglifyjs2对js进行压缩。目前很多框架的构建工具,如vue-cli,webpack等都已经在打包项目代码的时候进行了js压缩。
④ 文件合并:即将所要的请求,合并到一个文件,一起发送给客户端。不合并文件时,请求一次,返回一次,存在多次请求,多次返回,就会有网络延迟,网络故障.....等问题。合并文件时,将所有请求合并到一个文件,然后在一次性发送给后端,减少了网络请求的的次数以及频繁请求带来的问题,但是也会存在首屏渲染问题(因为是合并到一个文件里所有该文件较大,在第一次请求时,会存在较慢,如果浏览器需要根据请求返回的数据才进行渲染,即存在首屏加载渲染页面比较慢),以及缓存失效的问题(即多个文件合并到一个文件,如果其中一个文件发送细微的改变,那么合并后的文件都需要重新获取请求,即原合并后的缓存失效,解决:公共库的合并,不同页面的合并(单页面的合并))。
如何进行文件合并?:包括在线网站文件合并(如http://tool.oschina.net),nodejs实现合并。目前很多框架的构建工具,如vue-cli,webpack等都已经在打包项目代码的时候进行了文件合并。
1.1.2 掌握压缩与合并的原理:
1.1.3 通过在线网站和fis3两种方式实现优化:
① fis3:是百度的构建化的工具,是基于前端和后端一起的构建化工具(相比wepack更完整)。
1.2 浏览器的一个请求从发送到返回经历了什么?
文字解析:用户在浏览器中输入一个url,浏览器将url拆分解析,然后将解析后的domain发送到dns服务器上,dns服务器根据domain查询相关的ip地址,然后将ip地址返回给浏览器,浏览器然后将ip以及相关参数通过网络(局域网,路由器,主干网)发送到服务端,服务端有MVC架构,服务端通过model,redis+db返回view数据视图,最后返回render,在浏览器页面进行渲染html,css,html.....。
请求过程中潜在的性能优化点:dns是否可以通过缓存减少dns查询时间?网络请求过程中走最近的网络环境?相同的静态资源是否可以缓存?能否减少http请求大小?减少http请求次数?改为服务端渲染?
1.3 图片优化:
1.3.1:主要包括如下图片:
① 有损压缩:JPG格式的图片压缩,但是损失的部分,在肉眼上视觉上没有多大影响,压缩率较高,不支持透明。
② 无损压缩:PNG格式的图片压缩,支持透明,浏览器兼容好,存在降阶。
③ webp压缩:webp压缩程度更好,但在ios webview上有兼容问题,在安卓上很好的支持。
④ svg矢量图:通过HTML标签代码内嵌,相对较小,适用于图片样式相对简单的场景,如绘制logo。
⑤ 使用iconfont图标替代图片:通过使用iconfont替代图片,iconfont是用svg绘制。
1.3.2:在线压缩图片网站:如https://tinypng.com/。
1.3.3:在线图片格式转换:即png、webp相互转换,如https://zhitu.isux.us/。也可通过fis3插件配置在代码中,实现png、jpg、webp图片的格式的相互转换。
1.3.4:inline-image:即图片内嵌,将图片转换为 Data url base64格式,参考https://blog.csdn.net/u014465934/article/details/83750121。fis3中存在封装的__inline('img/1.webp')方法,可以直接将'img/1.webp'图片转换为图片内嵌。图片内嵌的特点:
① Data URI 替换 img src :减少外部资源Http请求,
② 使用 css background-image: url("data:image/gif;base64,R0lGODlhAwAD): 实现缓存
③ Data URI 转换后的图片的体积偏大 不适用于大图:适用于图片小于4M的图片。
#在fis3中
var inlineImage=__inline('img/1.webp');
<img src="'+inlineImage+'">
1.3.5:雪碧图:雪碧图css位置生成网站www.spritecow.com。将多张图片通过photoshop合并到一张图片上,可以减少http请求,但是会增加该图片的大小。
拓展:
png8/png24/png/32之间的区别:图片的大小,以及图片色彩的丰富度。
png8——256色+支持透明,大小较小。
png24——2^24色+不支持透明
png32——2^24色+支持透明
2.进阶优化:一个网站在浏览器端是如何进行渲染的?
2.1 html渲染的特点:
2.1.1:顺序执行,并发加载:html代码解析的顺序是从上到下执行的,即html是顺序执行的,html资源是并发请求的,在某个域名下,并发请求数是有上限的。
2.1.2:是否阻塞:css的加载是否阻塞后续Js的加载和执行,以及页面的渲染。js的加载是否阻塞后续Js的加载和执行.....,推荐css样式在html的head标签中通过link引入,在css加载完之前,后面的js的执行是会被阻塞的,css不阻塞外部脚本的加载(因为外部加载可以是异步加载,预加载)但是可能会阻塞执行。直接通过srcript引入js会阻塞页面的渲染(因为js可能会动态修改dom结构),js不阻塞资源的加载,js顺序执行,阻塞后续的js逻辑的执行。
2.1.3:依赖关系:HTML在渲染过程中依赖关系。如页面已经渲染出来,但是css还没加载完成,或css加载很慢,之后突然闪烁一下页面,然后css才加载完成并渲染到页面了,这是没有遵循好依赖关系。有比如js的执行是否存在依赖,a.js执行依赖b.js文件,如果a.js先加载完,但是b.js还没有加载,就会存在问题。
2.1.4:引入方式:动态异步的在某个时间点触发js的引入加载。
2.2 懒加载和预加载:
2.2.1:懒加载:即延迟加载资源,减少无效资源的加载,如电商类图片很多,页面很长,若没有进入用户可视区的图片,就暂时不用加载,进入用户可视区的图片才加载。包括原始js实现懒加载和第三方库zepto.lazyload.js实现懒加载
<!--
懒加载的原理:当图片出现在可视区内,就开始请求加载图片了。通过监听页面scroll,判断图片是否进入可视区,如果进入就开始懒加载该图片了
注意:1.图片一定要有固体的宽高尺寸大小,才能懒加载。
2.初始化时,图片的src为空字符串。
3.图片的url初始化要存在自定义属性中,如data-original。
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>1. 原生js实现懒加载</title>
<style type="text/css">
.img-lists{
margin-left: 5%;
}
.pic{
width: 40%;
height: 400px;
margin-right: 5%;
display: inline-block;
height: 400px;
background: grey;
}
</style>
</head>
<body>
<div class="img-lists">
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
</div>
<script>
const heightVal=document.documentElement.clientHeight; //获取可视区的高,即页面body的高。
function lazyload(){
let ele=document.querySelectorAll('img[data-original][lazyload]'); //查找页面所有有[data-original][lazyload]这2个属性的图片标签。
Array.prototype.forEach.call(ele,function(item,index){
let obj; //声明变量用于存放当前图片的宽度尺寸数据
if(item.dataset.original ===''){
return
}else{
obj=item.getBoundingClientRect(); //获取当前图片的宽度尺寸数据
}
if(obj.bottom>=0 && obj.top<heightVal){ //如果当前图片在可视区之类
function(){
let img=new Image();
img.src=item.dataset.original;
img.onload=function(){
item.src=img.src;
}
item.removeAttribute('data-original')
item.removeAttribute('lazyload')
}()
}
})
}
lazyload()
window.addEventListener('scroll',lazyload)
</script>
</body>
</html>
<!--
懒加载的原理:当图片出现在可视区内,就开始请求加载图片了。通过监听页面scroll,判断图片是否进入可视区,如果进入就开始懒加载该图片了
注意:1.图片一定要有固体的宽高尺寸大小,才能懒加载。
2.初始化时,图片的src为空字符串。
3.图片的url初始化要存在自定义属性中,如data-original。
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>2.zepto.lazyload.js实现懒加载</title>
<style type="text/css">
.img-lists{
margin-left: 5%;
}
.pic{
width: 40%;
height: 400px;
margin-right: 5%;
display: inline-block;
height: 400px;
background: grey;
}
</style>
</head>
<body>
<div class="img-lists">
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
<img src="" class="pic" data-original='http://pic31.nipic.com/20130801/11604791_100539834000_2.jpg' lazyload='true'/>
</div>
<script src='./zepto.lazyload.js'></script>
<script src='./zepto.min.js'></script>
<script>
$('img[data-original][lazyload]').lazyload()
</script>
</body>
</html>
2.2.2:预加载:即提前加载资源,然后在缓存中就可以直接使用资源,如H5项目中,提前加载好图片资源,以免切换动画效果时,出现空白情况。四种预加载的方式:
① 直接在img标签的src中加载:先隐藏该图片,需要的时候再显示,即可从缓存中读取该图片
<!--方式1:直接在img标签的src中加载,先隐藏该图片,需要的时候再显示,即可从缓存中读取该图片-->
<img src="http://pic41.nipic.com/20140508/18609517_112216473140_2.jpg" style='display:none'/>
② 使用Image对象加载:使用new Image() 事先加载好图片,在需要的时候,从缓存中获取。
//方式二:使用new Image() 事先加载好图片,在需要的时候,从缓存中获取
var img=new Image()
img.src="http://pic41.nipic.com/20140508/18609517_112216473140_2.jpg"
document.getElementById('myimage').src=img.src; //预先加载好图片,在需要的时候,从缓存中获取
③ XMLHttpRequest:可以更好处理图片请求的整个过程,但是存在跨域的问题。
var xml=new XMLHttpRequest();
xml.onreadystatechange=callback;
xml.onprogress=progressCallback;
xml.open('GET','http://pic41.nipic.com/20140508/18609517_112216473140_2.jpg',True);
xml.send();
function callback(){
if(xml.readState==4 && xml.status==200){
var text=xml.responseText;
}else{
console.log('请求失败')
}
}
function progressCallback(e){
console.log(e)
console.log('查看预加载的过程')
}
④ 使用第三方库PreloadJS实现预加载:
<script src='./preload.min.js'></script>
<script>
var queue=new createjs.LoadQueue(false); //参数为true时(类似xmlHttpRequest加载),存在跨域问题,为false时类似标签加载(img/new Image)。
queue.on('complete',handleComplete,this);
queue.loadManifest([
{
id:'myImage1',src='http://img.redocn.com/sheying/20150213/mulanweichangcaoyuanfengjing_3951976.jpg'
},{
id:'myImage2',src='http://img.redocn.com/sheying/20150213/mulanweichangcaoyuanfengjing_3951976.jpg'
}
])
function handleComplete(){
var image=queue.getRequest('myImage1');
document.body.appendChild(image);
}
</script>
2.3 浏览器的重绘与回流:
2.3.1 css性能让js变慢?一个线程执行ui渲染,一个线程执行js,原本是2个分开的线程,理论上不应该相互阻塞,但是js可能获取或修改ui渲染的结果,就使得浏览器在执行js时,会冻结ui线程,在执行ui渲染时,会冻结js线程执行,从而形成阻塞。频繁的触发重绘与回流,会导致UI频繁渲染,最终导致js变慢。
2.3.2 什么是回流:当render tree(dom树)中的一部分(或全部)因为元素的大小尺寸,布局位置,隐藏显示等改变而需要重新构建,即为回流。当页面布局和几何属性改变时,都会触发回流。一些元素的css会触发回流,如:盒子模型相关属性,定位属性及浮动,改变文字结构。
2.3.3 什么是重绘:当render tree(dom树)中的一部分(或全部)元素的属性更新改变,从而影响元素的外观,风格,而不会影响大小布局的,即为重绘。一些元素的css会触发重绘,如背景颜色,字体颜色,内外边框,边框阴影等。
2.3.4 解决重绘回流带来的性能问题方案:
① 避免使用触发重绘回流的css属性。
② 将重绘回流的影响范围限制在单独的图层内,video和canvas会自动创建图层。
③ 使用translate代替top:因为top/left/bottom/right.....的值变动会改变元素布局,引发回流重绘,而translate不会触发回流(即不会触发layout回流过程),只会触发重绘(paint)。
④ 使用opcaity替代visibility:因为visibility只会触发重绘,而opcaity不会(前提示该元素是单独独立出来的图层如添加transform:translateZ(0),或添加will-change:transform变成了图层) 。
⑤ 多使用class替代一天一天修改dom样式:因为每修改一条dom样式,会触发一次重绘。
⑥ 让dom离线后修改:如先把dom样式改为display:none(会触发一次回流),之后可以修改n次dom样式,不会触发回流重绘,再最后dom样式全部修改完在让其显示。
⑦ 不要让dom节点属性值放在一个循环里当成循环里的变量:如循环里获取offsetHeight/offsetWidth,会刷新缓存区,获取最新的dom的offsetHeight/offsetWidth,会触发回流,因为回流也有缓存机制。
⑧ 尽量不用table,可以用div替代:因为一个很小的改动会触发table重新布局,即触发回流重绘。
⑨ 动画的速度:动画效果会触发回流重绘,所以需要选择合适的动画速度。
⑩ 新增图层:图层里面的元素改变,只会触发当前图层的回流重绘,不会影响其他图层,chorme会根据性能自动新增图层。
⑾ 启动GPU硬件加速:合适的GPU加速,不易过多。
拓展:
1、回流必定引起重绘,重绘不一定引起回流。
2、将普通元素变成图层的方式:尽量在需要时候,添加图层,页面大量的图层会影响性能,因为图层合成上会花费很多时间。
1.1 添加transform:translateZ(0)。
1.2 添加will-change:transform。
2.4 浏览器的缓存机制:包括cookie,localstorage,sessionStorage,indexedDB等。
2.4.1 cookie:因为http请求是无状态的,所以需要cookie去维护客户端和服务端的状态。即同一域名下每次请求(包括静态资源的请求,如css,js,图片视频等)都会携带cookie,因为不是每次请求都需要cookie的,所以大量无效的cookie请求,造成了流量的耗损(解决:将静态资源和主站分别放在不同的域名下,即每次请求主站资源会携带cookie,请求静态资源,因为是不在同一域名下,不携带cookie)。cookie是服务端的set-cookie生成,返回给在浏览器中存储。且cookie大小只有4KB左右存储空间。cookie左右存储数据的作用被localstorage替代,所有cookie只常被用于保持和服务端通信的状态。
docuemnt.cookie //cookie的获取,设置,修改
2.4.2 localstorage:是H5中专门用于浏览器端存储数据的,大小为5KB左右。仅在浏览器端使用。如用于localstorage缓存js文件,图标等,则不需要每次加载页面,都从服务端请求获取这类文件。
if(window.localStorage){
localstorage.getItem('name') //获取
localstorage.setItem('name','Ace') //设置,修改
}
var testjs=localstorage.getItem('testjs')
if(testjs){ //如果能从本地缓存中获取test.js文件就 直接执行该test.js文件
eval(testjs)
}else{ //如果本地缓存中不存在test.js文件,就异步请求获取test.js文件,并将获取的test.js文件缓存在本地
var xml=new XMLHttpRequest();
xml.onreadystatechange=callback;
xml.onprogress=progressCallback;
xml.open('GET','./test.js',True);
xml.send();
function callback(){
if(xml.readState==4 && xml.status==200){
var testjs=xml.responseText;
eval(testjs)
localstorage.setItem('testjs',testjs)
}else{
console.log('请求失败')
}
}
function progressCallback(e){
console.log(e)
console.log('查看预加载的过程')
}
}
2.4.3 sessionstorage:会话级别的浏览器缓存(即当前窗口/页面开启时,无论怎么刷新页面都存在缓存信息,但是关闭页面/窗口,缓存信息就会消失),大小约5KB,常用于表单数据的维护(如按步骤注册用户信息时,返回上一步,下一步之前填写的信息仍然存在)。
2.4.4 indexedDB:用于客户端存储大量的结构化数据(如数组对象格式的数据库表),比web storage存储结构化数据更优势,如应用的离线应用,即在无网络情况下,用户仍然能从本地indexedDB中获取部分数据信息,不会出现“无网络信息”的体验差的效果。参考https://www.cnblogs.com/dolphinX/p/3415761.html。
function AceIndexDB(name){
var indexdbObj=window.indexedDB.open(name) //建立打开indexedDB,返回打开后的对象
indexdbObj.onerror=function(e){
console.log('打开indexedDB失败')
}
indexdbObj.onsuccess=function(e){
console.log('打开indexedDB成功,创建一个indexedDB')
myDB.db=e.target.result;
myDB.db.close(); //关闭indexedDB
window.indexedDB.deleteDatabase( myDB.db); //删除indexedDB
}
indexdbObj.onupgradeneeded=function(){ //监听indexedDB的初始化(从无到有)和版本变化
var objStore= myDB.db.createObjectStore('books',keyPath:'isbn'); //创建一个ObjectStore对象,类似数据库的表名
var titleIndex=objStore.createIndex('by_title','title',{ //创建事务 操作ObjectStore
unique:True
})
var authorIndex=objStore.createIndex('by_author','author')
objStore.push({ //向ObjectStore中添加数据,类似数据库的列
title:'书名1',
author:"作者1",
isbn:12
})
}
}
var myDB={
name:"testdb",
version:'1.0.0',
db:null
}
AceIndexDB(myDB.name)
2.5 pwa和service worker应用:
2.5.1 pwa(progressive web app):是一种渐进式的web app的标志。目的是为了使得web app 更接近原生的安卓/ios的app应用。
2.5.2 service worker:是一个脚本,具有拦截和处理网络请求的能力,。常用于:
① 离线应用:通过拦截和处理网络请求的能力,当浏览器向服务端发送请求时(或无网络时),service worker拦截该请求,并查看service worker中是否存储该请求需要的相关数据,如果存储,就把service worker中的数据返会给浏览器,拦截住该请求再向服务端发送,即实现了离线应用。
案例1:service worker的离线应用
目录结构:
test
service-worker.js //serviceWorker的配置文件
app.js //serviceWorker的注册文件
main.css
serviceWorker.html //入口文件
⑴ 在serviceWorker.html文件中:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link src='main.css'></link>
</head>
<body>
<script src="./app.js"></script>
</body>
</html>
⑵ 在app.js文件中:
if(navigator.serviceWorker){ //如果浏览器支持serviceWorker,就注册serviceWorker
//注册配置好serviceWorker的文件路径'./service-worker.js',并设置其作用域'./'(即当前目录下的所有文件,都在'./service-worker.js'文件的拦截请求作用域中)。
navigator.serviceWorker.register('./service-worker.js',{scope:'./'}).then((res)=>{
console.log(res) //注册成功
}).catch((e)=>{
console.log(e) //注册失败
})
}else{
alert('浏览器不支持serviceWorker')
}
⑶ 在service-worker.js 文件中:
self.addEventListener('install',(e)=>{ //serviceWorker的监听install事件,app.js中已经注册serviceWorker,即实现将静态文件缓存在本地cache Storage中
e.waitUntil(
caches.open('app-v1').then((res)=>{ //caches是开启cache Storage实现缓存
return res.addAll([ //将app.js和main.css文件缓存在本地cache Storage中,以便service worker离线加载
'./app.js',
'./main.css',
'./service-worker.js'
])
})
)
})
self.addEventListener('fetch',(e)=>{ //serviceWorker的监听fetch事件,通过拦截请求,即实现将缓存在本地cache Storage中的静态文件读取出来执行,即实现离线引用
e.responseWith( //拦截请求,改变请求返回的数据
caches.match(e.request).then((res)=>{ //e.request是作用域下拦截的每个请求(如app.js,main.css文件请求)
if(res){ //如果这个请求再cache Storage缓存中匹配到拦截的请求,即当发出请求app.js文件时,在cache Storage缓存中匹配到该app.js文件,就直接return 该缓存中的app.js文件,不需要在向网络发送请求app.js文件
return res
}else{ //如果这个请求再cache Storage缓存中没有匹配到拦截的请求,就从网络上请求。
//fetch(url).then((res)=>{
//if(res){ //如果从网络中获取到数据,就将数据返回给页面,并缓存改数据在启cache Storage中
//catch
//}
//})
}
})
)
})
② 后台大量数据的处理:当程序存在与页面以及逻辑关联不大,且存在大量数据处理的程序时,会从主线程中独立出一个子线程在service worker中处理,而不影响主线程的继续执行。
3.结合服务端优化:客户端和服务器基于协商的自动缓存机制。是基于httpheader实现的一种缓存策略。
3.1 cache-control:控制缓存信息,让服务端和客户端保持缓存策略。其httpheader属性(即缓存策略)包括max-age,s-maxage,private,public,no-cache,no-store。
属性 | 作用 | 案例 |
max-age | 指定缓存的最大有效时间,在这段时间内,不会再向服务端发起请求,返回200。可以从缓存中获取这个请求的资源。 | cache-control:max-age=1230000 |
s-maxage | 指定特定类型的缓存的最大有效时间,在这段时间内,不会再向服务端发起请求,返回304。可以从缓存中获取这个请求的资源。优先级高于max-age。 | cache-control:s-maxage=1230000 |
no-cache | 向服务端发送请求,通过服务端判断当前缓存是否过期。 | cache-control:no-cache |
no-store | 不使用任何的缓存策略。 | cache-control:no-store |
3.2 expires:设置缓存过期时间点,是服务端的具体时间点,即在过期时间点之前,就无需再次向服务端发送请求,其优先级低于max-age。
3.3 last-modified和if-modified-since:基于客户端和服务端协商通信的缓存机制(请求资源修改时间的变动,精确到秒)。缺点:服务端有时不能准确获得请求资源修改变动时间,且如果请求资源修改时间变动了,但是资源内容没有改变,这时last-modified和if-modified-since的缓存机制,就会有问题。
3.4 ETag和If-None-Match:基于客户端和服务端协商通信的缓存机制(请求资源内容的改动)。和last-modified和if-modified-since机制一模一样,但是优先级比last-modified和if-modified-since更高,只是一个是以修改时间为基准,一个是以内容变动为基准。
4.回顾总结:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!