导语: 前几天发了一个前端优化的办法,看的人还挺多的,于是马上把它们深度总结一下,也方便以后自己翻阅学习。
一位优秀的前端工程师都必须懂得的前端优化技巧,你会几个?
前端优化是复杂的,针对方方面面的资源都有不同的方式。 我们先来明确一下前端优化的目的是什么 ?
1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。
2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。
接着,前端性能优化可以分为两大类分别是:
页面级别优化,包含了http请求数以及内联脚本位置优化,代码级别的优化,包含DOM操作优化,CSS选择符优化以及图片优化等这一点是最有效的,首先,我们先来了解请求是怎么样的?每个请求都是有成本的,既包含时间成本也包含资源成本。
一个完整的请求都需要经过 DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个 “漫长” 而复杂的过程。(如下图)
时间成本就是用户需要看到或者 “感受” 到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。所以请求越多,就会花费更多时间,更多资源,更多宽带。
至于你要怎么优化这个请求次数呢,这就是多方面因素影响的了。
根据你的网页页面结构,进行针对性优化。如果你的页面像百度首页一样简单,那么你的请求就会很少。对页面整体结构进行分析,拆分出不同的模块,比如拆分成轮播图、推荐信息列,用户资本信息等等,然后对一些进行合并请求等等。
合理设置 HTTP缓存缓存的力量是强大的,恰当的缓存设置可以大大的减少 HTTP请求。以首页为例,当浏览器没有缓存的时候访问一共会发出 205个请求,共 3M数据 (如下图)
而当第二次访问即浏览器已缓存之后访问则仅有 31个请求,共 280多 K数据 (如下图)。
那么怎样才算合理设置 ?原则很简单,能缓存越多越好,能缓存越久越好。例如:
1. 很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头 ; 2. 变化不频繁而又可能会变的资源可以使用 Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。
如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间。 图片压缩工具,链接:https://tinypng.com/,能够将图片压缩超过50%,而且画质稍微受一点影响而已。
css压缩工具,链接:https://c.runoob.com/front-end/52,能够将css压缩,极大的减少css的大小。
js压缩工具,链接:https://c.runoob.com/front-end/51,能够将js压缩,极大的减少js的大小。
合并 CSS,减少请求数的又一个好办法。
例如:
你可以写了三个css样式表 css_one.css , css_two.css , css_three.css 这样你就可以写一个主样式 style.css 把三个样式表都装进去: @import “css_one.css”; @import “css_two.css”; @import “css_three.css”;
然后你就可以只引用style.css就可以了,这样就能把css合并起来使用,将三个请求变成一个,不过要注意的是,这三个css里面不能出现相同类名。
同样,js也可以用这个方式合并起来。
通过这种办法把几张图片合并成一个,然后通过容器剪切出对应的图片。
这种办法特别的好,往往能把十多个图片请求变成一个,优化率1000%多,可以说是终极技能了,快快学会吧。
就是只把首屏的图片加载出来,还没浏览到的部分不加载,等你滑动看到它的时候再加载出来。
这种优化技巧特别普遍,淘宝,美团等等都是有用到这种优化。极大的加快了首屏加载速度,提高了用户体验。
lazy load网址:https://www.lazyloadjs.cn/
如果将 CSS放在其他地方比如body中,则浏览器有可能还未下载和解析到 CSS就已经开始渲染页面了,这就导致页面由无 CSS状态跳转到 CSS状态,用户体验比较糟糕。(也就是平时我们看到的乱屏,过了一两秒后布局才正常)
除此之外,有些浏览器会在 CSS下载完成后才开始渲染页面,如果 CSS放在靠下的位置则会导致浏览器将渲染时间推迟。
而js和dom页面渲染公用一个线程,如果把js放在前面的话,可能会阻塞住页面的渲染,导致dom渲染不出来(白屏时间长),用户体验极差。
在脚本中 document.images()、document.forms() 、getElementsByTagName()返回的都是 HTMLCollection类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有 length属性,也可以使用索引访问每一个元素。
不过它可不是一个数组,在访问性能上则比数组要差很多,原因是这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新执行这个查询从而更新查询结果。所谓的 “访问集合” 包括读取集合的 length属性、访问集合中的元素。
因此,当你需要遍历 HTML Collection的时候,尽量将它转为数组后再访问,以提高性能。即使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length属性、成员保存到局部变量后再使用局部变量。
例如:
var x = getElementsByTagName('div') var y = [] funtion deepclone() { //深克隆 return object } for(let i = 0; i<x.length; i++) { y.push(deepclone(x[i])) }代码块的行为实际上是修改了代码块中的 执行环境 ,将obj放在了其作用域链的最前端,在 with代码块中访问非局部变量是都是先从 obj上开始查找,如果没有再依次按作用域链向上查找,因此使用 with相当于增加了作用域链长度。而每次查找作用域链都是要消耗时间的,过长的作用域链会导致查找性能下降。
因此,除非你能肯定在 with代码中只访问 obj中的属性,否则慎用 with,替代的可以使用局部变量缓存需要访问的属性。
前文谈到了作用域链查找问题,这一点在循环中是尤其需要注意的问题。如果在循环中需要访问非本作用域下的变量时请在遍历之前用局部变量缓存该变量,并在遍历结束后再重写那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问时的查找次数是最多的,严重影响效率。
低效率的写法:
// 全局变量 var globalVar = 1; function myCallback(info){ for( var i = 100000; i--;){ //每次访问 globalVar 都需要查找到作用域链最顶端,本例中需要访问 100000 次 globalVar += i; }}更高效的写法:
// 全局变量 var globalVar = 1; function myCallback(info){ //局部变量缓存全局变量 var localVar = globalVar; for( var i = 100000; i--;){ //访问局部变量是最快的 localVar += i; } //本例中只需要访问 2次全局变量在函数中只需要将 globalVar中内容的值赋给localVar 中区 globalVar = localVar; }此外,要减少作用域链查找还应该减少闭包的使用。
我们学会,字符串是可以用+进行拼接的,但是这种性能很低,他的过程就是,重新开辟一个内存,然后拼接起来后复制给原来的字符串。
其实我们可以直接使用join(),直接把字符串拼接起来。
这样子写,就能够提高首屏速度,在需要的时候再import,能够提高性能。
补充: 微信搜索【web小馆】,回复全栈博客项目,即可获取项目源码和后续的实战文章教程。每天用最简单朴实的语言,潜移默化的提升你的计算机基础知识和前端技术。小米粥,一个专注的web全栈工程师,我们下期再见!