前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端开发总结:如何优化网站性能?

前端开发总结:如何优化网站性能?

作者头像
beifengtz
修改2019-06-05 10:35:01
9990
修改2019-06-05 10:35:01
举报
文章被收录于专栏:北风IT之路

本文是2018-10-10与blog.beifengtz.com发表的博客。

学前端这么久了,从一无所知到web网页的开发,自己也是踩了巨多的坑,自己也在不断的摸索中,短时间内可能不会再做前端了,毕竟java是我的主方向。总结一下web网站在性能提升方面前端能做些什么优化,其中有结合一些资料,也有自己的经验之谈,毕竟不是专门学前端的,有不对的地方敬请多多指教。

一、能用Class定义样式尽量不用ID

class和id是前端页面选择dom元素最常用的两种方式,对于如何合理的使用它们是一个问题。对于class类可以在页面多次定义,可以看作是一个数组,允许同一页面出现很多次,理论上浏览器查找起来比较慢;id是页面内唯一定义的,不可重复定义,理论上浏览器查找起来会比较快,比较只有一个。

但是在为dom元素赋予样式的时候能用class尽量不用id,两个原因:

  1. class重绘速度比id快;
  2. id不利于dom样式继承,并且id一般用于js脚本选择,class一般用于样式定义,分工明确便于管理。

有人做过这样的测试:在Windows系统上的Firefox 6上,测得了一个简单类选择器的(reflow figure)重绘速度为10.9ms,而ID选择器为12.5ms,所以事实上ID比类选择器重绘要慢一点点。

当然尽量少使用标签选择器,在一个标签选择器(a)的测试上显示,它比类或ID选择器的速度慢了很多。在一个嵌套很深的后代选择器的测试上,显示数据为440左右!从这里我们可以看出ID/类选择器 和 元素/后代选择器中间的差异较大,但是相互之间的差异较小。

效率上:

Class选择器 > ID选择器 > Tag选择器

优先级上:

ID选择器 > Class选择器 > Tag选择器

二、合理使用css选择器

本节参考自:https://www.w3cschool.cn/css/css-selector.html

1、避免使用class选择器限制id选择器

代码语言:javascript
复制
避免
button#backButton {…}
避免
.menu-left#newMenuIcon {…}
优先
#backButton {…}
优先
#newMenuIcon {…}

2、避免使用标签限制 class 选择器

代码语言:javascript
复制
避免
treecell.indented {…}
优先
.treecell-indented {…}
最好
.hierarchy-deep {…}

3、避免使用多层标签选择器。使用 class 选择器替换,减少css查找

代码语言:javascript
复制
避免
treeitem[mailfolder="true"] > treerow > treecell {…}
优先
.treecell-mailfolder {…}

4、避免使用子选择器

代码语言:javascript
复制
避免
treehead treerow treecell {…}
更好
treehead > treerow > treecell {…}
优先
.treecell-header {…}

5、使用继承

代码语言:javascript
复制
避免
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
优先
#bookmarkMenuItem { list-style-image: url(blah) }

在暑假做web前端培训的时候我就看过选择器的优化,当时我说的不是很清楚,这次稍微总结一下:

总的来说在选择器使用过程中有几个大忌做到就可以了

  1. 绝不用优先级低的选择器限制优先级高的选择器。比如说div .container这种,用标签选择器限制了类选择器,大大降低了浏览器查找的效率
  2. 尽量少使用层级关系。特别是子选择器的使用,当出现类似于这种*#box .container > .red p*情况,这样多层选择还不如干脆取一个新的class来代替它,虽然这样设置的优先级非常高但是效率会很低,一般层级有个两三层就可以了,最多不能超过三层。

三、不重复设置样式

CSS全名虽然是层叠样式表,意思是样式可以重复定义,但是我们在实际使用中尽量避免这种多层样式设置,比如说我要设置一个段落字体大小font-size:20px;,我们一般用一个外部样式表设置class给它定义就行了,只用class定义它的字体大小为20px我们对它字体大小的属性只层叠了两次,因为默认属性又一次。下面这种做法尽量避免:

html代码

代码语言:javascript
复制
<!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代码

代码语言:javascript
复制
.paragraph{
  font-size:15px;
}

上面是对一个段落字体大小设置的错误做法,默认属性有对p标签字体大小定义默认属性,内联样式、嵌入式、外部样式分别对其字体大小定义了,总共层叠了四次,但是有效的只有内联样式一次。这样的重复定义是无意义的,而且会增大浏览器开销,小页面可能不能体现出来它的鸡肋之处,但是当页面dom变得复杂的时候就一目了然了。

四、具有动画的元素尽量不用相对定位

我平时比较喜欢使用动画,使用过程中发现在设置了动画的元素position属性使用absolute或fixed性能会好很多。这是因为流式布局的页面下,一旦前面动画元素在执行动画时影响到了其他的元素的定位,它后面的所有元素均会跟着动,这样页面渲染给浏览器增加了极大的负担,非常消耗cpu和gpu,所以尽量对具有动画效果的元素定位设置为absolutefixed

五、动画分步加载

所有的动画执行都会很消耗内存,如果在页面一开始就同时执行很多动画就很容易出现卡顿现象。所以尽量设置动画延时分步骤执行动画,让动画执行有一定先后顺序,减轻cpu压力。如果页面较长,可结合滚动监听分步执行动画,让浏览器窗口滚动到该页面才执行动画,这样不但提升了渲染性能还增加了用户体验。

六、图片懒加载

很让人头疼的就是在页面一打开的时候需要加载很多图片,导致页面显示图片很慢而且页面可能会变卡。一般在页面一打开默认是一次性加载所有静态资源,如果页面图片较多可使用懒加载减轻第一次加载图片的压力。

这里顺便说一下懒加载实现的方法:将需要加载的图片路径放到元素的data中,比如<div data-image="图片路径"></div>,然后结合滚动监听,监听页面即将滑到需要加载的元素时,用js将data-image的值赋给元素的css background-url属性,这样就达到了懒加载效果。

七、减少http请求

在整个页面显示的过程中,只有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代码段里会截断首屏的内容。下载脚本时并行下载是被禁用的——即使使用了不同的主机名,也不会启用其他的下载。因为脚本可能修改页面内容,因此浏览器会等待;另外,也是为了保证脚本能够按照正确的顺序执行,因为后面的脚本可能与前面的脚本存在依赖关系,不按照顺序执行可能会产生错误。把脚本置底,这样可以让网页渲染所需要的内容尽快加载显示给用户。

十一、使用CDN加速

如果应用程序web服务器离用户更近,那么一个HTTP请求的响应时间将缩短。另一方面,如果组件web服务器离用户更近,则多个HTTP请求的响应时间将缩短。

CDN(内容发布网络)是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络慕课拥堵的测量。例如,CDN可能选择网络阶跃数最小的服务器,或者具有最短响应时间的服务器。

CDN还可以进行数据备份、扩展存储能力,进行缓存,同时有助于缓和Web流量峰值压力。

但是CDN也会有缺点:

  1. 响应时间可能会受到其他网站流量的影响。CDN服务提供商在其所有客户之间共享Web服务器组。
  2. 如果CDN服务质量下降了,那么你的工作质量也将下降
  3. 无法直接控制组件服务器

十二、减少DNS查找

当我们在浏览器的地址栏输入网址 www.beifnegtz.com,然后回车,回车这一瞬间到看到页面到底发生了什么呢?

域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

域名解析是页面加载的第一步,那么域名是如何解析的呢?以Chrome为例:

  1. Chrome浏览器 会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有 www.beifnegtz.com 对应的条目,而且没有过期,如果有且没有过期则解析到此结束。 注:我们怎么查看Chrome自身的缓存?可以使用 chrome://net-internals/#dns 来进行查看
  2. 如果浏览器自身的缓存里面没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索解析到此结束. 注:怎么查看操作系统自身的DNS缓存,以Windows系统为例,可以在命令行下使用 ipconfig /displaydns 来进行查看
  3. 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果有则解析成功。
  4. 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址),运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先是会找根域的DNS的IP地址(这个DNS服务器都内置13台根域的DNS的IP地址),找打根域的DNS地址,就会向其发起请求(请问www.beifnegtz.com这个域名的IP地址是多少啊?),根域发现这是一个顶级域com域的一个域名,于是就告诉运营商的DNS我不知道这个域名的IP地址,但是我知道com域的IP地址,你去找它去,于是运营商的DNS就得到了com域的IP地址,又向com域的IP地址发起了请求(请问www.beifnegtz.com这个域名的IP地址是多少?),com域这台服务器告诉运营商的DNS我不知道www.beifnegtz.com这个域名的IP地址,但是我知道beifnegtz.com这个域的DNS地址,你去找它去,于是运营商的DNS又向beifnegtz.com这个域名的DNS地址(这个一般就是由域名注册商提供的,像万网,新网等)发起请求(请问www.beifnegtz.com这个域名的IP地址是多少?),这个时候beifnegtz.com域的DNS服务器一查,诶,果真在我这里,于是就把找到的结果发送给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.beifnegtz.com这个域名对应的IP地址,并返回给Windows系统内核,内核又把结果返回给浏览器,终于浏览器拿到了www.beifnegtz.com对应的IP地址,该进行一步的动作了。

注:一般情况下是不会进行以下步骤的 如果经过以上的4个步骤,还没有解析成功,那么会进行如下步骤:

  1. 操作系统就会查找NetBIOS name Cache(NetBIOS名称缓存,就存在客户端电脑中的),那这个缓存有什么东西呢?凡是最近一段时间内和我成功通讯的计算机的计算机名和Ip地址,就都会存在这个缓存里面。什么情况下该步能解析成功呢?就是YUI Compressor工具压缩,这个工具是目前使用最多的js、css文件压缩工具,大部分在线网站的压缩后台其实也是用的它,它是用java写的,所以如果你想在本地压缩的话需要配置java环境,当然对于java开发者强推该工具,使用它需要输入一些命令,如果嫌麻烦可以像我一样写一个程序或者批处理文件,每次直接选择文件就可以了哈哈哈。该名称正好是几分钟前和我成功通信过,那么这一步就可以成功解析。
  2. 如果第5步也没有成功,那会查询WINS 服务器(是NETBIOS名称和IP地址对应的服务器)
  3. 如果第6步也没有查询成功,那么客户端就要进行广播查找
  4. 如果第7步也没有成功,那么客户端就读取LMHOSTS文件(和HOSTS文件同一个目录下,写法也一样)

如果第八步还没有解析成功,那么就宣告这次解析失败,那就无法跟目标计算机进行通信。只要这八步中有一步可以解析成功,那就可以成功和目标计算机进行通信。

十三、压缩js、css、图片

减小请求资源的体积大小无疑是最直接的办法,我一般在做网页时都会将这些资源进行压缩,压缩js和css文件推荐使用Yahoo的YUI Compressor工具压缩,这个工具是目前使用最多的js、css文件压缩工具,大部分在线网站的压缩后台其实也是用的它,它是用java写的,所以如果你想在本地压缩的话需要配置java环境,当然对于java开发者强推该工具,使用它需要输入一些命令,如果嫌麻烦可以像我一样写一个程序或者批处理文件,每次直接选择文件就可以了哈哈哈。

压缩js和css不但可以起到减小文件大小的作用,在安全方面还有一定作用,可以混淆其中的变量、注释等,至少增大了第三者翻译源代码的难度。

十四、使用Ajax缓存

Ajax是我平时使用最多一个工具,其全面是“Asynchronous JavaScript and XML”(异步的JavaScript与XML),Ajax的目地是为突破web本质的开始—停止交互方式,向用户显示一个白屏后重绘整个页面不是一种好的用户体验。

POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(可以在服务器端对数据进行缓存,以便提高处理速度)

GET的请求,是可以(而且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。

提高Ajax性能的措施中最重要的方法就是使响应具有可缓存性(为文件头指定ExpiresCache-Control )

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 北风IT之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、能用Class定义样式尽量不用ID
  • 二、合理使用css选择器
  • 三、不重复设置样式
  • 四、具有动画的元素尽量不用相对定位
  • 五、动画分步加载
  • 六、图片懒加载
  • 七、减少http请求
  • 八、尽量使用外联样式
  • 九、样式表放在头部
  • 十、脚本放在尾部
  • 十一、使用CDN加速
  • 十二、减少DNS查找
  • 十三、压缩js、css、图片
  • 十四、使用Ajax缓存
相关产品与服务
内容分发网络 CDN
内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档