web前端页面性能优化笔记(包括缓存,资源压缩合并,server worker等) - Go语言中文社区

web前端页面性能优化笔记(包括缓存,资源压缩合并,server worker等)


添加小程序,兑换各种视频教程/数据资源。

包括:资源的合并与压缩,图片编码原理和类型选择,浏览器的渲染机制,懒加载预加载,浏览器存储,缓存机制,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.回顾总结:

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_42231156/article/details/97116135
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-14 20:48:53
  • 阅读 ( 1120 )
  • 分类:前端

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢