web
前端应用的开发与部署过程:javascript
输入url
到页面显示出来的过程:css
请求过程当中一些潜在的性能优化点:html
dns
是否能够经过缓存减小dns
查询时间?http
请求的大小和次数?总结:深刻理解http
请求的过程是前端性能优化的核心。前端
优化核心vue
http
请求数量;google
首页案例学习java
html
压缩;css
压缩;js
的压缩和混乱;gzip
;html
压缩HTML
代码压缩就是压缩一些在文本文件中有意义,可是在HTML
中不显示的字符,包括空格,制表符,换行符等,还有一些其余意义的字符,如HTML
注释也能够被压缩;node
一个简单的计算:webpack
google
的流量,占到整个互联网的40%
,预计2016
年全球网络流量将达到1.3ZB(1ZB = 10^9TB)
,那么google
在2016
年的流量就是1.3ZB * 40%
,若是google
每1MB
请求减小一个字节,每一年能够节省流量近500TB
流量。ios
如何进行html
压缩git
nodejs
提供的html-minifier
工具;css
代码压缩分为两部分:
css
语义合并;如何进行css
压缩
html-minifier
对html
中的css
进行压缩;clean-css
对css
进行压缩;js
压缩与混乱(丑化)包括:
JS
压缩与混乱(丑化)
html-minifier
对html
中的js
进行压缩;uglify.js2
对js
进行压缩;文件合并的好处:
左边的表示使用http
长连接keep-alive
但不合并请求的状况,须要分三次去获取a.js
、b.js
、c.js
;右边是使用长连接而且合并请求的状况,只须要发送一次获取合并文件a-b-c.js
的请求,就能将三个文件都请求回来。
不合并请求有下列缺点:
N-1
个网络延迟;keep-alive
自己也存在问题:通过代理服务器时可能会被断开;文件合并存在的问题
js
文件的时候,若是页面渲染只依赖a.js
文件,因为文件合并,须要等待合并后的a-b-c.js
文件请求回来才能继续渲染,这样就会致使页面渲染速度变慢。这种状况大多出如今现代化的前端框架,如Vue
等的使用过程当中;a-b-c.js
中只要其中一个文件(好比a.js
)发生变化,那么整个合并文件都将失效,而不采用文件合并就不会出现这种状况;使用建议
js
文件单独合并:好比在单页面应用SPA
中,当路由跳转到具体的页面时才请求该页面须要的js
文件;如何进行文件合并
nodejs
实现文件合并;webpack
等前端构件化工具也能够很好地实现;有损压缩过程:
一张JPG
图片的解析分别要进行:
RGB
的颜色空间转到其余的颜色空间 ;DCT
过程:对高频的颜色采样结果进行压缩,这样压缩的收益会比较大;encoding
);最终获得JPEG-Compressed Image Data
,即真正显示出来的JPG
图片。虽然这是一种有损压缩,可是不少状况下,这些损失的数据并不影响显示;
png8/png24/png32
之间的区别
png8
:256
色 +
支持透明;png24
:2^24
色 +
不支持透明;png32
:2^32
色 +
支持透明;不一样格式图片经常使用的业务场景
jpg
有损压缩,压缩率高,支持透明;应用:大部分不须要透明图片的业务场景;png
支持透明,浏览器兼容好;应用:大部分须要透明图片的业务场景;webp
(2010
年由谷歌推出)压缩程度更好,在ios webview
中有兼容性问题;应用:安卓所有;svg
矢量图,代码内嵌,相对较小,用于图片样式相对简单的场景;应用:好比logo
和iconfont
;针对真实图片状况,舍弃一些相对可有可无的色彩信息,对图片进行压缩;好比在线压缩网站:https://tinypng.com/
css
雪碧图将网站上用到的一些图片整合到一张单独的图片中,从而减小网站HTTP
请求数量。原理为:设定整张雪碧图可示区域,将想要显示的图标定位到该处(左上角);缺点:整合图片比较大时,一次加载比较慢。
如天猫的雪碧图:
不少状况下,并非全部的小图标都放在一张雪碧图中,而是会适当进行拆分。如今使用雪碧图的场景比较少了。
自动生成雪碧图样式的网站:http://www.spritecow.com/
选中雪碧图中对应的图标,就会生成对应的样式。
Image inline
)将图片的内容内嵌到html
当中,减小网站的HTTP
请求数量,经常使用于处理小图标和背景图片。网页内联图片写法为:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..." alt="">
浏览器上的表现形式为:
这里提供一个将:image
转 DataUrI
的网址:http://tool.c7sky.com/datauri/
缺点:
ie8
以上浏览器;1000kb
的图片,base64
编码会使图片大小增大,致使网页总体下载速度减慢;因此要根据场景使用,不过内联图片减小HTTP
请求的优势仍是很显著的。好比,在开发中小于4KB
或8KB
的图片都会经过构建工具自动inline
到HTML
中,这种状况下Image inline
带来的图片大小增加实际上是比增长HTTP
请求次数更优的。
SVG
与iconfont
使用iconfont
解决icon
问题
应尽可能使用该方式,好比能够采用阿里巴巴矢量图库:
能够选择格式进行下载:
能够看到它们的大小有着明显的差别:
使用SVG
进行矢量图的控制
SVG
意为可缩放矢量图形(Scalable Vector Graphics
)。SVG
使用 XML
格式定义图像。下为示例:
在线转换网站:http://www.bejson.com/convert/image_to_svg/
webp
webp
的优点体如今它具备更优的图像压缩算法,能带来更小的图片体积,并且拥有肉眼识别无差别的图像质量;同时具有了无损和有损的压缩模式、Alpha
透明以及动画的特性。在JPEG
和PNG
上的转化效果都很是优秀、稳定和统一。安卓上不存在兼容性问题,推荐安卓下使用。
如下为淘宝网首页请求的图片:
能够看到,图片中大量地添加了webp
格式的选择。.jpg_.webp
表示当浏览器支持webp
时采用webp
格式,不然采用jpg
格式。
下面为B
站首页的图片,能够看到基本都采用了webp
格式:
同一张图片jpg
格式和webp
格式压缩率有着明显的差别:
能够经过在线网站将图片转换为webp
:https://zhitu.isux.us/
像图片这样的静态文件能够存放在CDN
服务器上,让CDN
服务器批量地将图片转换成Webp
格式;
版本一:
版本二:
一个渲染引擎主要包括:HTML
解析器,CSS
解析器,javascript
引擎,布局layout
模块,绘图模块:
HTML
解析器:解释HTML
文档的解析器,主要做用是将HTML
文本解释成DOM
树;CSS
解析器:它的做用是为DOM
中的各个元素对象计算出样式信息,为布局提供基础设施;Javascript
引擎:使用Javascript
代码能够修改网页的内容,也能修改css
的信息,javascript
引擎可以解释javascript
代码,并经过DOM
接口和CSS
树接口来修改网页内容和样式信息,从而改变渲染的结果;layout
):在DOM
建立以后,Webkit
须要将其中的元素对象一样式信息结合起来,计算他们的大小位置等布局信息,造成一个能表达这全部信息的内部表示模型;paint
):使用图形库将布局计算后的各个网页的节点绘制成图像结果;浏览器渲染页面的整个过程:浏览器会从上到下解析文档。
浏览器解析时碰见 HTML
标记,就会调用HTML
解析器解析为对应的 token
(一个token
就是一个标签文本的序列化)并构建 DOM
树(就是一块内存,保存着tokens
,创建它们之间的关系)。在生成DOM
的最开始阶段(应该是Bytes
→ characters
后),并行发起css
、图片、js
的请求,不管他们是否在HEAD
标签中。
注意:发起
js
文件的下载请求(request
)并不须要DOM
处理到那个script
节点;
碰见 style/link
标记 调用解析器 处理 CSS
标记并构建 CSS
样式树;
碰见 script
标记 调用 javascript
解析器处理script
标记,绑定事件、修改DOM
树/CSS
树等;
将 DOM
树 与 CSS
树 合并成一棵渲染树(Render Tree
)。
布局(Layout
):根据渲染树中各节点的样式和依赖关系,计算出每一个节点在屏幕中的位置;
绘图(Painting
):按照计算出来的结果:要显示的节点、节点的CSS
与位置信息,经过显卡,把内容画到屏幕上;
通过第一次Painting
以后DOM
、CSSOM
、Render Tree
均可能会被屡次更新,好比JS
修改了DOM
或者CSS
属性时,Layout
和Painting
就会被重复执行。除了DOM
、CSSOM
更新的缘由外,图片下载完成后也须要调用Layout
和 Painting
来更新网页。
补充:
HTML
中可能会引入不少的css、js
这样的外部资源,这些外部资源在浏览器端是并发加载的。可是浏览器会对同一域名进行并发数量(度)的限制,即单个域名的并发度是有限的;- 因此,常常将大部分的资源托管到
CDN
服务器上,而且设置3~4
个CDN
域名。防止只有一个CDN
域名的状况下,达到了浏览器外部资源并发请求数目的上限,致使不少资源没法作到并发请求。因此,应设置多个CDN
域名;
css
阻塞只有经过link
引入的外部css
才会产生阻塞:
style
标签中的样式:
html
解析器进行解析;DOM
解析;link
引入的外部css
样式(推荐使用的方式):
CSS
解析器进行解析;css
已经加载完毕,因此整个渲染过程是带样式的,因此这种阻塞能够避免“闪屏现象”;js
语句的执行:这个不难理解,js
文件中常常会出现DOM
操做,操做过程当中有可能涉及到css
样式的修改。实际上,这些修改每每是依赖于以前引入的css
设定的样式的,因此css
会阻塞js
的执行;优化核心理念:尽量快的提升外部css
加载速度:
CDN
节点进行外部资源加速;css
进行压缩(利用打包工具,好比webpack
,gulp
等);http
请求数,将多个css
文件合并;js
阻塞阻塞DOM解析:
缘由:浏览器不知道后续脚本的内容,若是先去解析了下面的DOM
,而随后的js
删除了后面全部的DOM
,那么浏览器就作了无用功,浏览器没法预估脚本里面具体作了什么操做,例如像document.write
这种操做,索性所有停住,等脚本执行完了,浏览器再继续向下解析DOM
;能够经过给script
标签添加defer
和async
属性,异步引入js
文件,以此来解决这一问题。
阻塞页面渲染:
缘由:js
中也能够给DOM
设置样式,浏览器一样等该脚本执行完毕,再继续干活,避免作无用功;
阻塞后续js
的执行:
缘由:js
是按顺序执行的,这样能够维护依赖关系,例如:必须先引入jQuery
再引入bootstrap
;
不阻塞资源的加载:
这并不与上面矛盾,由于不可能因为加载一个js
文件就把其余资源的加载都阻塞了。针对这种常见的状况,浏览器会经过预加载的方式加载后续的资源;
css
的解析和js
的执行是互斥的(互相排斥),css
解析的时候js
中止执行,js
执行的时候css
中止解析;
不管css
阻塞,仍是js
阻塞,都不会阻塞浏览器加载外部资源(图片、视频、样式、脚本等);
由于览器始终处于一种:“先把请求发出去”的工做模式,只要是涉及到网络请求的内容,不管是:图片、样式、脚本,都会先发送请求去获取资源,至于资源到本地以后何时用,由浏览器本身协调。显然这种作法效率很高;
WebKit
和Firefox
都进行了【预解析】这项优化。在执行js
脚本时,浏览器的其余线程会解析文档的其他部分,找出并加载须要经过网络加载的其余资源。经过这种方式,资源能够在并行链接上加载,从而提升整体速度。请注意,预解析器不会修改 DOM
树
图片进入可视区域以后再请求图片资源的方式称为图片懒加载。适用于图片不少,页面很长的业务场景,好比电商;
懒加载的做用:
减小无效资源的加载:
好比一个网站有十页图片,用户只查看了第一页的图片,这就不必将十页图片全都加载出来;
并发加载的资源过多会阻塞js
的加载,影响网站正常的使用:
因为浏览器对某一个host name
是有并发度上限的,若是图片资源所在的CDN
和静态资源所在的CDN
是同一个的话,过多图片的并发加载就会阻塞后续js
文件的并发加载。
懒加载实现的原理:
监听onscroll
事件,判断可视区域位置:
图片的加载是依赖于src
路径的,首先能够为全部懒加载的静态资源添加自定义属性字段,用于存储真实的url
。好比是图片的话,能够定义data-src
属性存储真实的图片地址,src
指向loading
的图片或占位符。而后当资源进入视口的时候,才将src
属性值替换成data-src
中存放的真实url
。
<img src="" class="image-item" alt="" lazyload = "true" data-src="TB27YQvbm_I8KJjy0FoXXaFnVXa_!!400677031.jpg_180x180xzq90.jpg_.webp">
懒加载实例
能够使用元素的getBoundingRect().top
来判断当前位置是否在视口内,也能够使用元素距离文档顶部的距离offsetTop
和scrollTop
是否小于视口高度来判断:
举例
好比手机淘宝首页:
当快要滚动到须要展现的图片时才进行图片的请求,能够看到图片上有一个lazyload
的属性:
预加载与懒加载正好是相反的过程:懒加载其实是延迟加载,将咱们所需的静态资源加载时间延后;而预加载是将图片等静态资源在使用以前的提早请求,这样资源在使用到时能从缓存中直接加载,从而提高用户体验;
预加载的做用:
提早请求资源,提高加载速度:使用时只须要读取浏览器缓存中提早请求到的资源便可;
维护页面的依赖关系:好比WebGL
页面,会依赖一些3D
模型,这些都是页面渲染所必须的资源。若是资源都没有加载完毕就进行页面的渲染,就会形成很是很差的体验。
因此时常使用预加载的方式维护页面渲染的依赖关系,好比将WebGL
页面依赖的3D
模型加载完以后才进行页面渲染。这样渲染的过程就不会有任何阻碍,具备较好的用户体验;
预加载的实例
例如九宫格抽奖业务,每一个奖品都有一个选中态和非选中态,实际上这是由两张图片组合而成的。因为每一个奖品的选中过程都是一瞬间,这就对图片的选中态和非选中态切换效率要求很高,若是选中态的图片没有预加载的话显然是来不及的。
因此,实际上对于九宫格中全部图片选中态的样式和对应的图片都须要进行预加载,从而让咱们在抽奖的过程当中,可以瞬间从缓存中读取到选中态的图片,从而不影响抽奖效果的展现。
除此以外还有网站登陆或活动时须要用到的动画,这是在动画须要的每帧图片都彻底预加载完以后才会进行显示的。
CSS
图层浏览器在渲染一个页面时,会将页面分为不少个图层,图层有大有小,每一个图层上有一个或多个节点。在渲染 DOM
的时候,浏览器所作的工做其实是:
一、获取DOM
后分割为多个图层;
二、对每一个图层的节点计算样式结果(Recalculate style
--样式重计算);
三、为每一个节点生成图形和位置(Layout
--回流和重布局);
四、将每一个节点绘制填充到图层位图中(Paint Setup
和Paint
--重绘);
五、图层做为纹理上传至GUI
;
六、复合多个图层到页面上生成最终屏幕图像(Composive Layers
--图层重组);
3D
或透视变换的css
属性(prespective transform
);<video>
节点;3D(WebGL)
上下文或加速的2D
上下文的<canvas>
节点;CSS3
动画的插件(如Flash
);css
过滤器的元素;
transform
:如translateZ(0)
opacity
filter
will-change
:哪个属性即将发生变化,进而进行优化。重绘是一个元素外观的改变所触发的浏览器行为,好比background-color
、outline
等属性。这些属性不影响布局,只影响元素的外观,风格,会形成DOM
元素的从新渲染,这个过程称为重绘。
须要注意的是:重绘是以图层为单位,若是图层中某个元素须要重绘,那么整个图层都须要重绘。好比一个图层包含不少节点,其中有个gif
图,gif
图的每一帧,都会重回整个图层的其余节点,而后生成最终的图层位图。
所以,能够经过特殊的方式来强制gif
图单独为一个图层(translateZ(0)
或者translate3d(0,0,0)
;CSS3
的动画也是同样(好在绝大部分状况浏览器本身会为CSS3
动画的节点建立图层);
因此:将频繁重绘回流的DOM
元素做为一个独立图层,那么这个DOM
元素的重绘和回流只会该图层;原则上是要尽可能避免新建图层的,由于这会致使图层重组(Composive Layers
)时候的计算量增大。因此,只有当某些DOM
元素频繁重绘回流时,才新建一个独立图层放置它们;
只会触发重绘的属性
//部分属性 color border-style border-radius visibility text-decoration background background-image background-position background-repeat background-size outline-color outline outline-style outline-width box-shadow
当render tree
中的一部分(或所有)由于元素的规模尺寸,布局,隐藏等改变而须要从新构建。这就称为回流(reflow
);
当页面布局和几何属性改变时就须要回流;
回流必将引发重绘,而重绘不必定会引发回流;
触发页面重布局(回流)的属性
盒子模型相关属性 | 定位及浮动属性 | 文字结构属性 |
---|---|---|
width | top | text-align |
height | bottom | overflow-y |
padding | left | font-weight |
margin | right | overflow |
display | position | font-family |
border-width | float | line-height |
border | clear | vertical-align |
min-height | * | white-space |
* | * | font-size |
频繁触发重绘和回流,会致使UI
频繁渲染。在渲染的过程当中因为阻塞了js
线程的执行,最终致使js
执行变慢。
增长、删除、修改 DOM
结点;
移动 DOM
的位置;
修改 CSS
样式;
Resize
窗口;移动端没有这个问题,由于移动端的缩放没有影响布局视口(vw/vh
);
修改网页的默认字体;
获取某些DOM
元素的属性(width
,height
等);
注:
display:none
会触发Reflow
,而visibility:hidden
只会触发Repaint
,由于没有发生位置变化;
案例一:淘宝轮播图
能够使用Chrome
浏览器调试工具的Performance
来观察淘宝首页一个轮播图引发的重绘回流过程:
Update Layer Tree
回流和重布局:
Paint
重绘:
Composite Layers
图层重组:
案例二:播放器
经过Chrome
调试工具的Layers
选项查看图层,及新增图层的缘由:
视频播放的过程当中,video
标签的DOM
元素会一直重绘,因此把它限制在一个图层上是很是好的,这样只会涉及到这个图层的重绘,而不会影响其余图层的元素。
图层不能滥用,不然会在图层重组的过程当中严重消耗性能!
好比能够将淘宝首页的全部的DOM
元素都变为一个图层:在html
标签中的全局样式(*
)中添加transform:translateZ(0)
来触发新建图层:
还能够经过添加:
will-change: transform
属性新建图层;
再次查看此时的图层状况,能够看到此时首页的图层很是之多,十分地卡:
若是咱们须要使得动画或其余节点渲染的性能提升,须要作的就是减小浏览器在运行时所须要作的下列工做:
Recalculate style
--样式重计算);Layout
--回流和重布局);Paint Setup
和Paint
--重绘);Composite Layers
--图层重组);一、使用translate
替代top
等属性来改变位置;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box{ /*方法1*/ position: relative; top: 0; /*方法2*/ /* transform: translateY(0); */ width: 200px; height: 200px; background-color: pink; } </style> </head> <body> <div id="box"></div> <script> setTimeout(() => { document.getElementById("box").style.top = '100px' //document.getElementById("box").style.transform = 'translateY(100px)' }, 2000); </script> </body> </html>
使用top
属性改变正方形位置时,存在重绘和回流Layout
:
而使用translate
属性改变正方形位置时,并不会引发重绘和回流:
好比有的网站会有一些左右飘动的浮窗,因为这些浮窗是采用定时器来实现的,若是每通过100ms
就改变浮窗的位置。这种时候使用transform
来替代top/left
的话1s
内就减小了十次回流,十分有利于网页速度的提高。
二、使用opacity
替代visibility
:
使用visibility
不触发重排,可是依然重绘;
直接使用opacity
既触发重绘,又触发重排(GPU
底层设计如此!);
opacity
配合图层使用,既不触发重绘也不触发重排;
缘由:透明度的改变时,GPU
在绘画时只是简单的下降以前已经画好的纹理的alpha
值来达到效果,并不须要总体的重绘。不过这个前提是这个被修改opacity
自己必须是一个单独的图层。
三、将屡次改变DOM
元素样式属性的操做合并成一次操做:
class
,而后经过修改DOM
的className
来添加样式;四、把DOM
离线后再修改:
display
属性为none
的元素不在渲染树中,对隐藏的元素操做不会引起其余元素的重排。若是要对一个元素进行复杂的操做时,能够先隐藏它,操做完成后再显示。这样只在隐藏和显示时触发2
次回流;五、不要把获取某些DOM
节点的属性值放在一个循环里当成循环的变量
当向浏览器请求某些 style
信息的时候,浏览器就会清空(flush
)队列,好比:
ffsetTop
,offsetLeft
,offsetWidth
,offsetHeight
;
scrollTop/Left/Width/Height
;
clientTop/Left/Width/Height
;
width
,height
;
浏览器为了获取最精确的值,须要刷新内部队列。由于队列中可能存在影响到这些值的操做,即便没有,浏览器也会强行刷新渲染队列。这样就没法利用渲染队列的缓存来避免回流过于频繁了,因此在使用到DOM
元素这些相关的属性时,能够将获取到的属性值存在一个变量中,而不是每次都去从新获取。
六、不要使用table
布局:
table
的从新布局;因此尽可能使用div
布局;七、启用GPU
硬件加速:
原理为:浏览器会检测一些特定的css
属性,当DOM
元素拥有这些css
属性的时候,浏览器就会对该DOM
元素启动GPU
硬件加速;好比:transform: translateZ(0)
和transform: translate3d(0, 0, 0)
这两个属性均可以启动硬件加速;硬件加速一样不能滥用,不然会致使图层过多,致使合并图层时消耗大量性能。
八、动画实现速度的选择:
九、为动画元素新建图层,提升动画元素的z-index
;
十、利用文档碎片(documentFragment
)------vue
使用了该种方式提高性能
若是咱们要在一个ul
中添加10000
个li
,若是不使用文档碎片,那么咱们就须要使用append
进行10000
次的追加,这会致使页面不停地回流,很是地消耗资源:
var oUl = document.createElement("ul"); for(var i=0;i<10000;i++) { var oLi = document.createElement("li"); oUl.appendChild(oLi); } document.body.appendChild(oUl);
咱们能够引入createDocumentFragment()
方法,它的做用是建立一个文档碎片。先将要插入10000
个li
添加到文档碎片里,而后再一次性添加到document
中。即文档碎片至关于一个临时仓库,这样可以大量减小DOM
操做:
//先建立文档碎片 var oFragment = document.createDocumentFragment(); //再建立ul标签 var oUl = document.createElement("ul"); for(var i=0;i<10000;i++) { //建立li标签 var oLi = document.createElement("li"); //先附加在文档碎片中 oFragment.appendChild(oLi); } //将文档碎片添加到ul标签中 oUl.appendChild(oFragment); //将ul标签添加到body标签中 document.body.appendChild(oUl);
十、使用requestAnimationFrame
制做动画:详细内容以下。
requestAnimationFrame
)window.requestAnimationFrame()
:该方法会告诉浏览器在重绘以前调用指定的函数:
参数:该方法以一个回调函数做为参数,这个回调函数会在浏览器重绘以前被调用;
回调函数会被自动传入一个参数:DOMHighResTimeStamp
,标识requestAnimationFrame()
开始触发回调函数的当前时间;
返回值: 一个非零的整数,也称为请求ID
,是回调列表中惟一的标识,没有其余意义;
window.cancelAnimationFrame(requestID)
:该方法取消一个先前经过调用window.requestAnimationFrame()
方法添加到计划中的动画帧请求。requestID
是先前调用window.requestAnimationFrame()
方法时返回的ID
。
用途
CSS3
制做动画的状况下,使用这种方法替代定时器制做动画;示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box{ height: 200px; width: 200px; background-color: pink; } </style> </head> <body> <div id="box"></div> <script> let i = 0 //获取请求ID let id = requestAnimationFrame(move) function move(){ i++ document.getElementById('box').style.transform = `translateX(${i}px)` //递归调用requestAnimationFrame,更新请求ID,实现动画效果 id = requestAnimationFrame(move) } setTimeout(() => { //2s后中止动画 cancelAnimationFrame(id) }, 2000); </script> </body> </html>
代码实现
function debounce(fn,delay){ var timer = null // 清除上一次延时器 return function(){ clearTimeout(timer) // 从新设置一个新的延时器 timer = setTimeout(() => { fn.call(this) }, delay); } }
使用函数防抖能够减小事件触发的次数和频率,在某些状况下能够起到优化的做用。好比:搜索框,对于核心业务非搜索的网站,通常都是等待用户完整输入内容后才发送查询请求,一次来减小服务器的压力。像百度这样的核心业务为搜索的网站,服务器性能足够强大,因此不进行函数防抖处理;
概念:不断触发一个函数后,执行第一次,只有大于设定的执行周期后才会执行第二次,以此控制函数执行频率;
实现:定时器,标识;
应用:在游戏中,能够设定人物攻击动做的最快频率,不管手速多快也没法超越这一频率;
代码实现
/* 节流函数:fn:要被节流的函数,delay:规定的时间 */ function throttle(fn, delay){ // 记录上一次函数出发的时间 var lastTime = 0 return function(){ // 记录当前函数触发的时间 var nowTime = new Date().getTime() // 当当前时间减去上一次执行时间大于这个指定间隔时间才让他触发这个函数 if(nowTime - lastTime > delay){ // 绑定this指向 fn.call(this) //同步时间 lastTime = nowTime } } }
Cookie
Cookie
翻译过来是小甜饼的意思,是网景公司的前雇员 Lou Montulli
在1993
年3
月发明的;Cookie
是纯文本格式,不包含任何可执行的代码信息,伴随着用户请求在 Web
服务器和浏览器之间传递;Cookie
本质上属于http
的范畴,由于http
协议自己是无状态的,服务端是没有办法区分请求来自于哪一个客户端,即使是来自于同一个客户端的屡次请求,服务端也没法进行区分。因此引入了Cookie
去维持客户端的状态(好比每一个帐号的购物车状态都不同)。Cookie
的生成方式
客户端生成:
在 JavaScript
中经过 document.cookie
属性,你能够建立、维护和删除 Cookie
;设置 document.cookie
属性的值并不会删除存储在页面中的全部 Cookie
,它只简单的建立或修改字符串中指定的 Cookie
。
服务端生成:
Web
服务器经过在HTTP
响应头中添加 Set-Cookie
字段来建立一个 Cookie
,能够在该字段中添加HttpOnly
属性禁止JavaScript
脚本访问Cookie
,以此来避免跨域脚本 (XSS
) 攻击。
Cookie
的缺陷
Cookie
在HTTP
中是明文传递的,其中包含的数据均可以被他人访问,出现篡改、盗用等问题;Cookie
的大小限制在4KB
左右,若要作大量存储显然不是理想的选择;Cookie
是绑定域名对应的服务器的,因此对同一个域名的每次请求都会在Request Header
中带上Cookie
。
Cookie
信息的场合下流量的浪费;这样浏览器对同一域名的每一次请求都会多出4KB
流量,对于大型网站来讲这是很大的损耗。所以要慎用Cookie
,不要在Cookie
中存储重要和敏感的数据。
Cookie
性能优化的方法
将存放静态资源的CDN
服务器域名与主站的域名独立开来。这样每次请求静态文件的时候就不须要携带Cookie
,从而能够节省不少流量。
举例
好比在百度进行登陆的时候,请求头里面就会有Set-Cookie
字段,其中的BDUSS
就是标识用户登陆状态的字符串:
Set-Cookie
中的httponly
属性表示的是禁止js
脚本访问cookie
,这样可以必定程度防范XSS
攻击;
在Chrome
调试工具的Application
选项中查看Cookies
信息,能够发现该Cookie
已经被网站“种”到Domain:.baidu.com
这个域名下了,而且该Cookie
也设置了HttpOnly
属性:
此后浏览器的每次请求都会在请求头Request Headers
中携带这一Cookie
信息。刷新页面后能够看到,请求头中携带了Cookie
信息BDUSS
:
这样服务器就知道这是已经登陆的用户了。
可是不是全部的请求都须要携带Cookie
信息,好比优酷:
能够看到请求index.css
文件时也携带了Cookie
,可是这是没必要要的,这就会致使流量的浪费。
解决方法就是上面所说的:将
CDN
域名和主域名独立出来;
百度就是这样解决的:
能够看到请求这个静态资源的url
并非.baidu.com
,而是静态资源服务器CDN
;而且该请求的请求头中不会携带Cookie
信息:
设置和获取Cookie
设置Cookie
的方式很简单,key
和value
值经过等号链接:
document.cookie = "userName=zhangsan"
打开Application
选项查看当前Cookie
,能够看到Cookie
已被改变:
获取Cookie
:
document.cookie
备注:
- 静态资源是不会携带
Cookie
的;Cookie
通常都是后台种的,不多让前端来直接写;Cookie
分:持久级别、session
级别;Cookie
通常用于存放session ID
与服务器端进行通讯;
Web Storage
Web Storage
分为SessionStorage
和LocalStorage
专门用于客户端浏览器的本地存储,同时空间比Cookie
大不少,通常支持5-10M
;
浏览器端经过 Window.sessionStorage
和 Window.localStorage
属性来实现本地存储机制;
LocalStorage
LocalStorage
是HTML5
设计出来专门用于存储浏览器信息的:
5~10M
左右;js
进行读写等操做的API
;举例
好比经过Chrome
调试工具的Application
选项能够查看淘宝中LocalStorage
存储的数据:
这些数据只要不手动清除,即便关闭页面也都会存在。当须要使用图片、js/css
文件等资源时就不用从新向服务器发出请求,而是能够直接使用LocalStorage
中的缓存,这就是LocalStorage
缓存的优点;
而Cookie
就不同了,里面存储的数据都是要带到服务器端的,例如用户登陆状态,统计信息等数据:
设置和获取LocalStorage
LocalStorage
提供了相对简单的API
,采用的也是key
和value
的形式。
设置时经过:
localStorage.setItem("key", "value")
查看LocalStorage
,一样设置成功了:
获取时经过:
localStorage.getItem("key")
其余方法
//该方法接受一个键名做为参数,并把该键名从存储中删除。 localStorage.removeItem('key'); //调用该方法会清空存储中的全部键名 localStorage.clear();
SessionStorage
SessionStorage
用于存储浏览器的会话信息,标签页关闭以后它存储的数据就会被清空,而LocalStorage
的数据不会被清空,这是两者的区别:
5~10M
左右;SessionStorage
中,这样即便刷新后数据也不会丢失;还有一种场景:分页的表单在进行前进或后退时,若是将信息保存在SessionStorage
中就不会丢失;设置和获取SessionStorage
设置SessionStorage
的方法与设置LocalStorage
的方法相似:
//设置 sessionStorage.setItem("key", "value") //获取 sessionStorage.getItem("key")
经过Application
选项查看SessionStorage
,可见已成功修改:
其余方法
//该方法接受一个键名做为参数,并把该键名从存储中删除。 sessionStorage.removeItem('key'); //调用该方法会清空存储中的全部键名 sessionStorage.clear();
IndexedDB
IndexedDB
是浏览器提供的一种API
,用于存储客户端中大量的结构化数据。该API
使用索引来实现对数据的高性能搜索。虽然WebStorage
对于存储较少许的数据时颇有用(采用key/value
的方式),但对于存储更大量的结构化数据来讲,仍是IndexedDB
表现更加优异。
IndexedDB
的应用
能够在浏览器中打印indexedDB
对象:
PWA
PWA
(Progressive Web Apps
)是一种Web App
新模型(标准),并非具体指某一种前沿的技术或者某一个单一的知识点。从英文缩写就能看出,这是一个渐进式的Web App
,是经过一系列新的Web
特性,配合优秀的UI
交互设计,逐步加强用户的体验;
PWA
的要求
Engaging
):应用能够被增长到手机桌面,而且和普通应用同样有全屏、推送等特性;Service Worker
Service Worker
是一个脚本,能够使浏览器独立于当前网页,在后台运行。为实现一些不依赖页面或者用户交互的特性打开了一扇大门。在将来这些特性将包括推送信息,背景后台同步,geofencing
(地理围栏定位)等它将推出的第一个首要特性,就是拦截和处理网络请求的能力,包括以编程方式来管理被缓存的响应。
即Service Worker
能够帮助浏览器执行大规模的运算而不阻碍主线程的执行。
Service Worker
的应用
Service Worker
在后台运行的同时能和页面通讯的能力,去实现大规模后台数据的处理;Service Worker
应用过程
示例
经过Chrome
调试工具的Application
选项能够查看淘宝的Service Workers
信息:
当咱们刷新淘宝网页的时候,查看Network
选项,能够从请求文件的size
栏发现大量的文件都是从Service Worker
缓存中请求回来的:
这样的话就能够利用Service Worker
的缓存进行网站的性能优化。
如下列淘宝请求同一js
文件为例,从Service Worker
中加载使用了7ms
:
使用Ctrl + F5
强制刷新后,向服务器请求同一文件花了100ms
:
这就是使用Service Worker
性能上带来的优点。因为是从本地缓存中读取的资源,因此资源读取的速度和总体的性能都会有一个明显的提高。
缓存定义:
浏览器在本地磁盘上将用户以前请求的数据存储起来,当访问者再次须要改数据的时候无需再次发送请求,直接从浏览器本地获取数据
缓存的好处:
能够经过Chrome
浏览器调试工具中的Network
选项查看浏览器请求资源的状况:
注意不要勾选图中方框内的选项,不然有些请求会被过滤;
Cache-Control
字段服务器可经过httpheader
中的Cache-Control
字段控制客户端与服务器端之间的缓存策略,它的属性值有:
max-age
该字段指定了缓存的最大有效时间,如下为淘宝的一张图片:
在max-age
属性指定的时间未到期前,客户端不会向服务器发起请求,而是从缓存中直接读取该图片。上图中能够看到浏览器直接从ServiceWorker
的缓存中读取了该图片资源。
Expires
字段一样能够指定缓存的有效期,不过这是HTTP1.0
中的字段,优先级比HTTP1.1
中的Cache-Control
字段的max-age
属性低;
s-maxage
缓存设备整体来讲有两种:浏览器(客户端)和CDN
服务器;
private
类型缓存设备,表示只有浏览器才能够对资源进行缓存;CDN
服务器属于public
类型缓存设备,这种设备能够对源服务器上的资源进行缓存。而且,这种缓存对于任何用户来讲都是能够访问的;s-maxage
的优先级在Expires
和max-age
三者之中是最高的,用于指定public
类型缓存设备(好比CDN
)上资源的有效期。以下图所示,该资源设定了该字段后,浏览器既不会使用浏览器缓存,也不会向服务器请求资源,而是向public
类型的缓存设备(如CDN
服务器)请求资源:
private
服务器端能够经过该属性指定某一资源只能被浏览器(客户端)缓存,而不能被代理缓存服务器(CDN
)缓存。
public
服务器端能够经过该属性指定某一资源,既能够被浏览器缓存,也能够被代理缓存服务器缓存;
no-cache
no-cache
属性规定了浏览器要先向服务器端发送请求确认缓存资源的新鲜度,才能决定是否使用缓存;以下图所示:
no-store
该属性指定了浏览器不管缓存资源是否过时直接跳过缓存,从新向服务器请求资源。no-store
属性用的比较少。
Expires
字段这是http1.0
的规范;它的值为一个绝对时间的GMT
(格林威治标准时间)格式时间字符串,如Mon, 10 Jun 2015 21:31:12 GMT
;
该字段指定了浏览器缓存资源的过时时间,在指定的时间到期前,浏览器能够直接从本地缓存中读取数据,而无需再次向服务器发起请求,属于强缓存;相比于max-age
与s-maxage
优先级最低,在这两个属性存在的状况下Expires
字段会失效;
Last-Modified/If-Modified-Since
两者是基于客户端和服务端协商的缓存机制,标识资源最后更新时间的字段。last-modified
字段位于response header
中,If-Modified-Since
字段位于request header
中,两者配合着Cache-Control
字段使用。
当服务器上的资源发生改变时会同步更新last-modified
的字段值,当Expires
字段或max-age
属性指定的时间到期后,客户端会在请求头中携带If-Modified-Since
字段,与服务器端资源的last-modified
字段值进行比较:
last-modified
字段指定的时间之后都没有发生变化,此时服务器返回状态码304
,属于协商缓存;last-modified
字段值,此时的状态码为200
;举例
下图表示状态码为304
的响应:
If-Modified-Since
字段的值为Mon, 23 Mar 2020 18:14:15 GMT
:Last-Modified
字段的值为Mon, 23 Mar 2020 18:14:15 GMT
:两者相等,说明资源没有发生变化,因此服务器返回状态码304
,属于协商缓存,浏览器继续使用本地缓存;
If-Modified-Since
字段的值就是服务器端上一次响应资源中的Last-Modified
字段值;
Last-Modified
的缺点
GET
;1s
内修改了N
次),If-Modified-Since
能检查到的粒度是s
级的,这种修改没法判断(好比淘宝每ms
都会更新数据);因此有了
Etag/If-None-Match
Etag
字段是HTTP1.1
中的标准,是一个惟一标识服务器端资源的hash
值,该字段存在于响应头(reponse header
)中;与请求头(request header
)中的If-None-Match
字段及Cache-Control
字段配合使用。
只要服务器端的资源发生变化Etag
值就会改变,相比于Last-Modified
字段优先级更高且更有效;当Expires
值或者Cache-Control
字段中的max-age
值到期时,客户端会在请求头中携带If-None-Match
字段,该字段值为服务器端上一次响应资源中的Etag
值,并与服务器端上最新资源的Etag
值进行比较:
304
,属于协商缓存;Etag
值,此时状态码为200
;举例
下图表示状态码为304
的响应:
If-None-Match
字段值为2da25d4039...
:Etag
字段值为2da25d4039...
:两者相等,说明资源没有发生变化,因此服务器返回状态码304
,属于协商缓存,浏览器继续使用本地缓存;
总结:
利用
Etag
可以更加准确的控制缓存,由于Etag
是服务器自动生成或者由开发者生成的对应资源在服务器端的惟一标识符;
Last-Modified
与ETag
是能够一块儿使用的,因为Etag
的优先度更高,因此服务器会优先比较Etag
和If-None-Match
。一致的状况下,才会继续比对Last-Modified
和If-Modified-Since
,最后才决定是否返回状态码304
。
强缓存:
200 ok(from memory cache)
;协商缓存:
304
通知浏览器从缓存中读取资源;缓存 | 获取资源形式 | 状态码 | 发送请求到服务器 |
---|---|---|---|
强缓存 | 从缓存中获取 | 200(from cache) |
否,直接从缓存中获取 |
协商缓存 | 从缓存中获取 | 304(not modified) |
是,根据服务器返回信息判断缓存是否可用 |
最下层的200
状态
这一层由Expires/Cache-Control
字段控制:
1.Expires
(HTTP1.0
版本有效)是绝对时间;
2.Cache-Control
(HTTP1.1
版本有效)是相对时间;
当二者都存在时,Cache-Control
会覆盖Expires
,只要这些字段没有失效,浏览器都会直接使用本地缓存,属于强缓存;
缓存的来源大概有两种memory cache
和disk cache
:
能够看到,从memory cache
中读取缓存不须要时间,从disk cache
中读取缓存则须要必定时间。
相对时间与绝对时间与服务器的设置有关,当服务器设置
Atime
(最后访问时间)时,两者相等;当服务器设置Mtime
(绝对修改时间)时,Expires
从资源的建立开始计算过时时间,Max-age
从请求发起的时间开始计算过时时间;
下图即是淘宝中采用强缓存的例子,状态码为200
,图片资源都是从浏览器缓存memory cache
中读取,因此请求时间为0ms
:
中间的304
状态
last-modified/Etag
控制。当下一层失效时或用户点击refresh/F5
时,浏览器就会向服务器发起请求,若是服务器上的相关资源没有更新,则返回状态码304
,属于协商缓存;下图便为协商缓存的状况,状态码为304
。也能够这样理解:只要状态码是304
都属于协商缓存:
最上层的200
状态
Ctrl + F5
强制刷新时,浏览器会直接向服务器请求最新的资源;以下图所示:
用户操做 | Expires/Cache-Control |
Last-Modified/Etag |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面连接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进后退 | 有效 | 有效 |
F5 刷新 |
无效 | 有效 |
Ctrl + F5 强制刷新 |
无效 | 无效 |
如图所示,该流程图表示服务器端在处理资源时采用缓存策略的过程:
Cache-Control
字段中添加no-store
属性;Cache-Control
字段中添加no-cache
属性,这样无论缓存资源是否过时,都要求客户端或缓存代理服务器首先向服务器确认资源的新鲜度,属于协商缓存;Web
代理缓存资源(好比CDN
服务器缓存),若是容许则在Cache-Control
字段中添加public
属性,并指定代理缓存服务器上资源的有效期s-maxage
;不容许则添加private
属性,表示只能由客户端浏览器缓存资源,并设定缓存的有效期max-age
;CDN
服务器网站一般将其全部的服务器都放在同一个地方,当用户群增长时,公司就必须在多个地理位置不一样的服务器上部署内容。为了缩短http
请求的时间,咱们应该把大量的静态资源放置的离用户近一点。
内容发布网络CDN
(Content Delivery Networks
)就是其中一种方式。CDN
是一组分布在多个不一样地理位置或网段的web
服务器,用于更加有效的向用户发布内容。
CDN
系统可以实时地根据网络流量和各节点的链接、负载情况以及到用户的距离和响应时间等综合信息最简单的CDN
网络由一个DNS
服务器和几台缓存服务器组成:
URL
时,通过本地DNS
系统解析,DNS
系统最终会将域名的解析权交给CNAME
指向的CDN
专用的DNS
服务器;关于
DNS
解析,不必定由DNS
服务器响应,通常从缓存中读取。好比电脑缓存、浏览器缓存、路由器缓存、运行商缓存等。若是缓存中没有找到,才一级一级地查询:本地DNS
-> 权限DNS
-> 顶级DNS
-> 根DNS
。全球只有13
台根DNS
服务器。
二、CDN
的DNS
服务器将CDN
的全局负载均衡设备的IP
地址返回给用户;
三、用户向CDN
的全局负载均衡设备发起内容URL
访问请求;
四、CDN
全局负载均衡设备根据用户的IP
地址,以及用户请求的内容URL
,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求;
五、区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:
根据用户IP
地址,判断哪一台服务器距用户最近;
根据用户所请求的URL
中携带的内容名称,判断哪一台服务器上有用户所需内容;
查询各个服务器当前的负载状况,判断哪一台服务器尚有服务能力;
基于以上这些条件的综合分析以后,CDN
区域负载均衡设备会向CDN
全局负载均衡设备返回一台CDN
缓存服务器的IP
地址。
六、CDN
全局负载均衡设备把服务器的IP
地址返回给用户;
七、用户向CDN
缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端;若是这台CDN
缓存服务器上并无用户想要的内容,可是区域均衡设备依然将它分配给了用户,那么这台CDN
服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地;
网站站点/应用加速:
站点或者应用中大量静态资源的加速分发,建议将站点内容进行动静分离,动态文件能够结合云服务器ECS
,静态资源如各种型图片、html
、css
、js
文件等,使用CDN
服务器存储,能够有效加速内容加载速度,轻松搞定网站图片、短视频等内容分发。
移动应用加速:
移动APP
更新文件(apk
文件)分发,移动APP
内图片、页面、短视频、UGC
等内容的优化加速分发。提供httpDNS
服务,避免DNS
劫持并得到实时精确的DNS
解析结果,有效缩短用户访问时间,提高用户体验。
视音频点播/大文件下载分发加速;
视频直播加速;
简单点说CDN
服务器至关于顺丰快递分布于全国各地的仓库,主仓库将快递运送到这些分仓库,用户能够就近取货,由此加快了速度。
除此以外CDN
服务器还有许多高级功能,好比防止DDOS
攻击等,这里就不展开了;
SSR(Server Side Rendering)
依赖现代框架如Vue
和React
构建的网站,每每会存在必定的问题,好比Vue
框架。
Vue
渲染面临的问题
首屏渲染时,要先下载和解析app.js
(打包事后的Vue.js
)以后,才能开始渲染页面。
优化方案
Prerender
的方式;一般采用服务端渲染(SSR
)的方式进行优化。所谓SSR
就是利用服务器端优秀的计算能力,将一部分的页面渲染任务交由服务器端进行处理。如下为服务端渲染SSR
的流程图:
服务端渲染能够很好地优化首屏渲染的问题;能够根据业务需求,适当地分配客户端和服务器端的渲染部分,综合利用客户端和服务器端的计算能力,从而达到性能优化的目的。
参考资料: