本文是2018-10-10与blog.beifengtz.com发表的博客。
学前端这么久了,从一无所知到web网页的开发,自己也是踩了巨多的坑,自己也在不断的摸索中,短时间内可能不会再做前端了,毕竟java是我的主方向。总结一下web网站在性能提升方面前端能做些什么优化,其中有结合一些资料,也有自己的经验之谈,毕竟不是专门学前端的,有不对的地方敬请多多指教。
class和id是前端页面选择dom元素最常用的两种方式,对于如何合理的使用它们是一个问题。对于class类可以在页面多次定义,可以看作是一个数组,允许同一页面出现很多次,理论上浏览器查找起来比较慢;id是页面内唯一定义的,不可重复定义,理论上浏览器查找起来会比较快,比较只有一个。
但是在为dom元素赋予样式的时候能用class尽量不用id,两个原因:
有人做过这样的测试:在Windows系统上的Firefox 6上,测得了一个简单类选择器的(reflow figure)重绘速度为10.9ms,而ID选择器为12.5ms,所以事实上ID比类选择器重绘要慢一点点。
当然尽量少使用标签选择器,在一个标签选择器(a)的测试上显示,它比类或ID选择器的速度慢了很多。在一个嵌套很深的后代选择器的测试上,显示数据为440左右!从这里我们可以看出ID/类选择器 和 元素/后代选择器中间的差异较大,但是相互之间的差异较小。
效率上:
Class选择器 > ID选择器 > Tag选择器
优先级上:
ID选择器 > Class选择器 > Tag选择器
本节参考自:https://www.w3cschool.cn/css/css-selector.html
1、避免使用class选择器限制id选择器
避免
button#backButton {…}
避免
.menu-left#newMenuIcon {…}
优先
#backButton {…}
优先
#newMenuIcon {…}
2、避免使用标签限制 class 选择器
避免
treecell.indented {…}
优先
.treecell-indented {…}
最好
.hierarchy-deep {…}
3、避免使用多层标签选择器。使用 class 选择器替换,减少css查找
避免
treeitem[mailfolder="true"] > treerow > treecell {…}
优先
.treecell-mailfolder {…}
4、避免使用子选择器
避免
treehead treerow treecell {…}
更好
treehead > treerow > treecell {…}
优先
.treecell-header {…}
5、使用继承
避免
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
优先
#bookmarkMenuItem { list-style-image: url(blah) }
在暑假做web前端培训的时候我就看过选择器的优化,当时我说的不是很清楚,这次稍微总结一下:
总的来说在选择器使用过程中有几个大忌做到就可以了
CSS全名虽然是层叠样式表,意思是样式可以重复定义,但是我们在实际使用中尽量避免这种多层样式设置,比如说我要设置一个段落字体大小font-size:20px;,我们一般用一个外部样式表设置class给它定义就行了,只用class定义它的字体大小为20px我们对它字体大小的属性只层叠了两次,因为默认属性又一次。下面这种做法尽量避免:
html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>css性能优化</title>
<link rel="stylesheet" href="test.css">
<style>
.paragraph{
font-size: 18px;
}
</style>
</head>
<body>
<p class="paragraph" style="font-size: 20px">这是一个测试段落</p>
</body>
</html>
test.css代码
.paragraph{
font-size:15px;
}
上面是对一个段落字体大小设置的错误做法,默认属性有对p标签字体大小定义默认属性,内联样式、嵌入式、外部样式分别对其字体大小定义了,总共层叠了四次,但是有效的只有内联样式一次。这样的重复定义是无意义的,而且会增大浏览器开销,小页面可能不能体现出来它的鸡肋之处,但是当页面dom变得复杂的时候就一目了然了。
我平时比较喜欢使用动画,使用过程中发现在设置了动画的元素position属性使用absolute或fixed性能会好很多。这是因为流式布局的页面下,一旦前面动画元素在执行动画时影响到了其他的元素的定位,它后面的所有元素均会跟着动,这样页面渲染给浏览器增加了极大的负担,非常消耗cpu和gpu,所以尽量对具有动画效果的元素定位设置为absolute
或fixed
所有的动画执行都会很消耗内存,如果在页面一开始就同时执行很多动画就很容易出现卡顿现象。所以尽量设置动画延时分步骤执行动画,让动画执行有一定先后顺序,减轻cpu压力。如果页面较长,可结合滚动监听分步执行动画,让浏览器窗口滚动到该页面才执行动画,这样不但提升了渲染性能还增加了用户体验。
很让人头疼的就是在页面一打开的时候需要加载很多图片,导致页面显示图片很慢而且页面可能会变卡。一般在页面一打开默认是一次性加载所有静态资源,如果页面图片较多可使用懒加载减轻第一次加载图片的压力。
这里顺便说一下懒加载实现的方法:将需要加载的图片路径放到元素的data中,比如
<div data-image="图片路径"></div>
,然后结合滚动监听,监听页面即将滑到需要加载的元素时,用js将data-image的值赋给元素的css background-url属性,这样就达到了懒加载效果。
在整个页面显示的过程中,只有10%~20%的最终用户响应时间花在了下载HTML文档上。其余的80%~90%时间花在了下载页面中的所有组件上。而下载就得进行http请求,因此改善http请求远远比前面优化页面效果来的更好。
这样举一个例子,我现在有一个200KB的文件和两个100KB的文件,一次下载200KB的速度会比两次下载100KB的速度快很多。所以我们尽量将能合并的文件都合并,比如合并css样式表、合并js脚本、图片合并等等。特别是图片的合并,在一个页面一般都会有很多图标,而图标一般又是图片,比如页面有二十个图标那就要进行二十次http请求,如果我们把二十个图标合成一张图,用CSS Sprites或者图片地图来设置显示的图标,这样就只需一次http请求。
使用图片地图的缺点:指定坐标区域时,矩形或圆形比较容易指定,而其它形状手工指定比较难。
CSS Sprites直译过来就是CSS精灵,用background-position来定位图标。
前面虽然说了尽量减少http请求,但是在设置样式时尽量不使用内联样式或者嵌入式。首先我们一般写html代码和css代码是分开的,尽量不要融合到一起,这样会给你管理页面代码带来极大的负担。其次使用外联样式表可以运用浏览器缓存机制,从而在不同的请求内容之间重用,如果浏览器有该样式表的缓存就不会进行http请求。详细浏览器解析一次请求的过程请看下面减少DNS查找片段。
经样式表(css)放在网页的HEAD中会让网页显得加载速度更快,因为这样做可以使浏览器逐步加载已将下载的网页内容。这对内容比较多的网页尤其重要,用户不用一直等待在一个白屏上,而是可以先看已经下载的内容。如果将样式表放在底部,浏览器会拒绝渲染已经下载的网页,因为大多数浏览器在实现时都努力避免重绘,样式表中的内容是绘制网页的关键信息。
js的下载和执行会阻塞Dom树的构建(严谨地说是中断了Dom树的更新),所以script标签放在首屏范围内的HTML代码段里会截断首屏的内容。下载脚本时并行下载是被禁用的——即使使用了不同的主机名,也不会启用其他的下载。因为脚本可能修改页面内容,因此浏览器会等待;另外,也是为了保证脚本能够按照正确的顺序执行,因为后面的脚本可能与前面的脚本存在依赖关系,不按照顺序执行可能会产生错误。把脚本置底,这样可以让网页渲染所需要的内容尽快加载显示给用户。
如果应用程序web服务器离用户更近,那么一个HTTP请求的响应时间将缩短。另一方面,如果组件web服务器离用户更近,则多个HTTP请求的响应时间将缩短。
CDN(内容发布网络)是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络慕课拥堵的测量。例如,CDN可能选择网络阶跃数最小的服务器,或者具有最短响应时间的服务器。
CDN还可以进行数据备份、扩展存储能力,进行缓存,同时有助于缓和Web流量峰值压力。
但是CDN也会有缺点:
当我们在浏览器的地址栏输入网址 www.beifnegtz.com,然后回车,回车这一瞬间到看到页面到底发生了什么呢?
域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户
域名解析是页面加载的第一步,那么域名是如何解析的呢?以Chrome为例:
注:一般情况下是不会进行以下步骤的 如果经过以上的4个步骤,还没有解析成功,那么会进行如下步骤:
如果第八步还没有解析成功,那么就宣告这次解析失败,那就无法跟目标计算机进行通信。只要这八步中有一步可以解析成功,那就可以成功和目标计算机进行通信。
减小请求资源的体积大小无疑是最直接的办法,我一般在做网页时都会将这些资源进行压缩,压缩js和css文件推荐使用Yahoo的YUI Compressor工具压缩,这个工具是目前使用最多的js、css文件压缩工具,大部分在线网站的压缩后台其实也是用的它,它是用java写的,所以如果你想在本地压缩的话需要配置java环境,当然对于java开发者强推该工具,使用它需要输入一些命令,如果嫌麻烦可以像我一样写一个程序或者批处理文件,每次直接选择文件就可以了哈哈哈。
压缩js和css不但可以起到减小文件大小的作用,在安全方面还有一定作用,可以混淆其中的变量、注释等,至少增大了第三者翻译源代码的难度。
Ajax是我平时使用最多一个工具,其全面是“Asynchronous JavaScript and XML”(异步的JavaScript与XML),Ajax的目地是为突破web本质的开始—停止交互方式,向用户显示一个白屏后重绘整个页面不是一种好的用户体验。
POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(可以在服务器端对数据进行缓存,以便提高处理速度)
GET的请求,是可以(而且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。
提高Ajax性能的措施中最重要的方法就是使响应具有可缓存性(为文件头指定Expires或Cache-Control )