浅谈网页基本性能优化规则小结
这篇文章主要介绍了浅谈网页基本性能优化规则小结的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
针对浏览器网页的一些优化规则
页面优化
静态资源压缩
借助构建工具(webpack、gulp)适当压缩图片、脚本及样式等网页静态资源。
CSS雪碧图、base64内联图片
将站内小图标合并成一张图,使用css定位截取对应图标;适当使用内联图片。
样式置顶、脚本置底
页面是一个逐步呈现的过程,样式置顶能更快呈现页面给用户;<script> 标签置顶会阻塞页面后面资源的下载。
使用外链的css和js
多个页面引用公共静态资源,资源复用减少额外的http请求。
避免空src的图片
避免不必要的http请求。
`<!-- 空src的图片依然会发起http请求 -->` `<``img` `src``=``""` `alt``=``"image"` `/>`
避免在html中缩放图片
图片尽量按需求使用指定规格的尺寸,而不是加载一张大图片再将它缩小。
`<!-- 实际图片尺寸为600x300,在html中缩放为了200x100 -->` `<``img` `src``=``"/static/images/a.png"` `width``=``"200"` `height``=``"100"` `alt``=``"image"` `/>`
Preload预加载
给link标签的rel设置preload属性,可以让浏览器在主渲染机制介入前就预加载资源。这种机制可以更早的获取资源且不阻塞页面的初始化。
`<!DOCTYPE html>` `<``html` `lang``=``"en"``>` `<``head``>` `<``meta` `charset``=``"UTF-8"``>` `<``title``>Document</``title``>` `<``link` `ref``=``"preload"` `href``=``"style.css"` `as``=``"style"``>` `<``link` `ref``=``"preload"` `href``=``"main.js"` `as``=``"script"``>` `<``link` `ref``=``"stylesheet"` `href``=``"style.css"``>` `</``head``>` `<``body``>` `<``script` `src``=``"main.js"``></``script``>` `</``body``>` `</``html``>`
例子中预加载了css和js文件,在之后的页面渲染中,一旦使用它们就会立即调用。
可指定as的类型加载不同类型的资源。
- style
- script
- video
- audio
- image
- font
- document
- ...
该方式也可跨域预加载资源,设置crossorigin属性即可。
`<``link` `rel``=``"preload"` `href``=``"fonts/cicle_fina-webfont.woff2"` `as``=``"font"` `type``=``"font/woff2"` `crossorigin``=``"anonymous"``>`
CSS
选择器
选择器的优先级从高到低排列为:
- ID选择器
- 类选择器
- 标签选择器
- 相邻选择器
h
`1
+ p{
margin-top:` `15px
; }`选择紧接在h1元素后出现的段落,h1和p元素拥有共同的父元素。
子选择器
h
`1
> strong {color
:red
;}`后代选择器
h
`1
em {color
:red
;}`通配符选择器
属性选择器
`*[title] {``color``:``red``;}` `img[alt] {``border``:` `5px` `solid` `red``;}`
伪类选择器
选择器使用经验:
- 优先选择类选择器,可替代多层标签选择器;
- 慎用ID选择器,虽然它效率高,但是在页面中是唯一的,不利于团队协作和维护;
- 合理利用选择器的继承性;
- 避免css表达式。
减少选择器的层级
建立在上一条选择器的优先级之上,应尽量避免多层次的选择器嵌套,最好不要超过3层。
`.container .text .logo{` `color``:` `red``; }` `/*改成*/` `.container .text-logo{` `color``:` `red``; }`
精简页面样式文件,去掉不用的样式
浏览器会进行多余的样式匹配,影响渲染时间,另外样式文件过大也会影响加载速度。
利用css继承减少代码量
利用css的可继承属性,父元素设置了样式,子元素就不用再设置。
常见的可以继承的属性比如:color,font-size,font-family等;不可继承的比如:position,display,float等。
属性值为0时,不加单位
css属性值为0时,可不加单位,减少代码量。
`.text{` `width``:` `0px``;` `height``:` `0px``; }` `/*改成*/` `.text{` `width``:` `0``;` `height``:` `0``; }`
JavaScript
使用事件委托
给多个同类DOM元素绑定事件使用事件委托。
`<``ul` `id``=``"container"``>` `<``li` `class``=``"list"``>1</``li``>` `<``li` `class``=``"list"``>2</``li``>` `<``li` `class``=``"list"``>3</``li``>` `</``ul``>`
`// 不合理的方式:给每个元素都绑定click事件` `$(``'#container .list'``).on(``'click'``,` `function``() {` `var` `text = $(``this``).text();` `console.log(text);` `});`
// 事件委托方式:利用事件冒泡机制将事件统一委托给父元素
`$(``'#container'``).on(``'click'``,` `'.list'``,` `function``() {` `var` `text = $(``this``).text();` `console.log(text); ` `});`
需要注意的是,虽然使用事件委托时都可以将事件委托给document来做,但这是不合理的,一个是容易造成事件误判,另一个是作用域链查找效率低。应该选择最近的父元素作为委托对象。
使用事件委托除了性能上更优,动态创建的DOM元素也不需要再绑定事件。
DOMContentLoaded
可在DOM元素加载完毕(DOMContentLoaded)后开始处理DOM树,不必等到所有图片资源下载完后再处理。
`// 原生javascript` `document.addEventListener(``"DOMContentLoaded"``,` `function``(event) {` `console.log(``"DOM fully loaded and parsed"``);` `},` `false``);` `// jquery` `$(document).ready(``function``() {` `console.log(``"ready!"``);` `});` `// $(document).ready()的简化版` `$(``function``() {` `console.log(``"ready!"``);` `});` }//欢迎加入全栈开发交流划水交流圈:582735936 ]//面向划水1-3年前端人员 } //帮助突破划水瓶颈,提升思维能力
预加载和懒加载
预加载
利用浏览器空闲时间预先加载将来可能会用到的资源,如图片、样式、脚本。
无条件预加载
一旦onload触发,立即获取将来需要用到的资源。
图片资源预加载。(3种实现图片预加载的方式)。
基于用户行为的预加载
对于用户行为可能进行的操作进行判断,预先加载将来可能需要用到的资源。
- 当用户在搜索输入框输入时,预先加载搜索结果页可能用到的资源;
- 当用户去操作一个Tab选项卡时,默认显示其中一个,当要去点击(click)其他选项时,在鼠标hover时,就可先加载将来会用到的资源;
懒加载
除页面初始化需要的内容或组件之外,其他都可以延迟加载,如剪切图片的js库、不在可视范围的图片等等。
图片懒加载。(判断图片是否在可视区域范围内,若在,则将真实路径赋给图片)
避免全局查找
任何一个非局部变量在函数中被使用超过一次时,都应该将其存储为局部变量。
`function` `updateUI(){` `var` `imgs = document.getElementsByTagName(``"img"``);` `for` `(``var` `i=0, len=imgs.length; i < len; i++){` `imgs[i].title = document.title +` `" image "` `+ i;` `}` `var` `msg = document.getElementById(``"msg"``);` `msg.innerHTML =` `"Update complete."``;` `}`
在上面函数中多次使用到document全局变量,尤其在for循环中。因此将document全局变量存储为局部变量再使用是更优的方案。
`function` `updateUI(){` `var` `doc = document;` `var` `imgs = doc.getElementsByTagName(``"img"``);` `for` `(``var` `i=0, len=imgs.length; i < len; i++){` `imgs[i].title = doc.title +` `" image "` `+ i;` `}` `var` `msg = doc.getElementById(``"msg"``);` `msg.innerHTML =` `"Update complete."``;` `}` }//欢迎加入全栈开发交流划水交流圈:582735936 ]//面向划水1-3年前端人员 } //帮助突破划水瓶颈,提升思维能力
值得注意的一点是,在javascript代码中,任何没有使用var声明的变量都会变为全局变量,不正当的使用会带来性能问题。
避免不必要的属性查询
使用变量和数组要比访问对象上的属性更有效率,因为对象必须在原型链中对拥有该名称的属性进行搜索。
`// 使用数组` `var` `values = [5, 10];` `var` `sum = values[0] + values[1];` `alert(sum);` `// 使用对象` `var` `values = { first: 5, second: 10};` `var` `sum = values.first + values.second;` `alert(sum);`
上面代码中,使用对象属性来计算。一次两次的属性查找不会造成性能问题,但若需要多次查找,如在循环中,就会影响性能。
在获取单个值的多重属性查找时,如:
var
query = window.location.href.substring(window.location.href.indexOf(
`"?"`));
应该减少不必要的属性查找,将window.location.href缓存为变量。
`var` `url = window.location.href;` `var` `query = url.substring(url.indexOf(``"?"``));`
函数节流
假设有一个搜索框,给搜索框绑定onkeyup事件,这样每次鼠标抬起都会发送请求。而使用节流函数,能保证用户在输入时的指定时间内的连续多次操作只触发一次请求。
<
`input
type=
"text"
id=
"input"
value=
""
/>``// 绑定事件` `document.getElementById(``'input'``).addEventListener(``'keyup'``,` `function``() {` `throttle(search);` `},` `false``);` `// 逻辑函数` `function` `search() {` `console.log(``'search...'``);` `}` `// 节流函数` `function` `throttle(method, context) {` `clearTimeout(method.tId);` `method.tId = setTimeout(``function``() {` `method.call(context);` `}, 300);` `}`
节流函数的应用场景不局限搜索框,比如页面的滚动onscroll,拉伸窗口onresize等都应该使用节流函数提升性能。
最小化语句数
语句数量的多少也是影响操作执行速度的因素。
将多个变量声明合并为一个变量声明
`// 使用多个var声明` `var` `count = 5;` `var` `color =` `"blue"``;` `var` `values = [1,2,3];` `var` `now =` `new` `Date();` `// 改进后` `var` `count = 5,` `color =` `"blue"``,` `values = [1,2,3],` `now =` `new` `Date();`
改进的版本是只使用一个var声明,由逗号隔开。当变量很多时,只使用一个var声明要比单个var分别声明快很多。
使用数组和对象字面量
使用数组和对象字面量的方式代替逐条语句赋值的方式。
`var` `values =` `new` `Array();` `values[0] = 123;` `values[1] = 456;` `values[2] = 789;` `// 改进后` `var` `values = [123, 456, 789];` `var` `person =` `new` `Object();` `person.name =` `"Jack"``;` `person.age = 28;` `person.sayName =` `function``(){` `alert(``this``.name);` `};` `// 改进后` `var` `person = {` `name :` `"Jack"``,` `age : 28,` `sayName :` `function``(){` `alert(``this``.name);` `}` `};`
字符串优化
字符串拼接
早期浏览器未对加号拼接字符串方式优化。由于字符串是不可变的,就意味着要使用中间字符串来存储结果,因此频繁的创建和销毁字符串是导致它效率低下的原因。
`var` `text =` `"Hello"``;` `text+=` `" "``;` `text+=` `"World!"``;`
把字符串添加到数组中,再调用数组的join方法转成字符串,就避免了使用加法运算符。
`var` `arr = [],` `i = 0;` `arr[i++] =` `"Hello"``;` `arr[i++] =` `" "``;` `arr[i++] =` `"World!"``;` `var` `text = arr.join(``''``);`
现在的浏览器都对字符串加号拼接做了优化,所以在大多数情况下,加法运算符还是首选。
减少回流和重绘
在浏览器渲染过程中,涉及到回流和重绘,这是一个损耗性能的过程,应注意在脚本操作时减少会触发回流和重绘的动作。
- 回流:元素的几何属性发生了变化,需要重新构建渲染树。渲染树发生变化的过程,就叫回流;
- 重绘:元素的几何尺寸没有变化,某个元素的CSS样式(背景色或颜色)发生了变化。
触发重排或重绘的操作有哪些?
- 调整窗口大小
- 修改字体
- 增加或者移除样式表
- 内容变化,比如用户在<input/>框中输入文字
- 操作class属性
- 脚本操作DOM(增加、删除或修改DOM元素)
- 计算offsetWidth和offsetHeight属性
- 设置style属性的值
如何减少重排和重绘,提升网页性能?
1、脚本操作DOM元素
- 将DOM元素设置为display:none,设置过程中会触发一次回流,但之后可以随意改动,修改完后再显示;
- 将元素clone到内存中再进行操作,修改完后重新替换元素。
2、修改元素的样式
- 尽量批量修改,而不是逐条修改;
- 预先设定好id、class,再设置元素的className。
3、为元素添加动画时将元素CSS样式设为position:fixed或position:absolute,元素脱离文档流后不会引起回流。
4、在调整窗口大小、输入框输入、页面滚动等场景时使用节流函数(上面已提到过)。
HTTP
浏览器缓存
合理设置浏览器缓存是网页优化的重要手段之一。
Expires 和 Cache-Control
Expires出自HTTP1.0,Cache-Control出自HTTP1.1,同时设置两者时,Cache-Control 会覆盖 Expires。
- Expires指定的是实际过期日期而不是秒数。但Expires存在一些问题,如服务器时间不同步或不准确。所以最好使用剩余秒数而不是绝对时间来表达过期时间。
- Cache-Control可设置max-age值,单位秒,指定缓存过期时间。如:Cache-Control: max-age=3600。
ETag 和 Last-Modified
ETag 和 Last-Modified都由服务器返回在response headers中,其中ETag的优先级比Last-Modified高,也就是说服务器会优先判断ETag的值。
- ETag是附加到文档上的任意标签,可能是文档的序列号或版本号,或者是文档内容的校验等。当文档改变时ETag值也会随之改变。与ETag相关的是 If-None-Match,当浏览器发起请求时,会在If-None-Match字段携带ETag的值发给服务器;
- Last-Modified是文档在服务器端最后被修改的时间。与Last-Modified相关的是If-Modified-Since,当浏览器发起请求时,会在If-Modified-Since字段携带Last-Modified的值发送给服务器。
强缓存和协商缓存
缓存的类型强缓存和协商缓存。两者区别是,强缓存不会向服务器发请求,而协商缓存会发请求,匹配成功返回304 Not Modified,匹配不成功返回200;浏览器会先校验强缓存,若强缓存未命中,再进行协商缓存校验。
如何配置浏览器缓存
- 在web服务器的返回响应中添加Expires和Cache-Control;
- 在nginx或apache的配置文件中配置Expires和Cache-Control。
为什么要减少HTTP请求
在性能优化中减少http请求的措施占了很大部分,比如:使用css雪碧图代替多张图片的请求、避免空src的图片、使用内联图片、使用外链的css和js、缓存等。
从输入URL到页面加载完成的过程包括:
- DNS解析
- TCP连接
- HTTP请求与响应
- 浏览器渲染页面
- 关闭连接
一个完整的http请求要经历这些过程,它是耗时耗资源的,因此减少请求数就变得很有必要
本次给大家推荐一个免费的交流圈,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
对web开发技术感兴趣的同学,欢迎加入,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。