前端性能优化总结(一)-js、css优化

html-css015

前端性能优化总结(一)-js、css优化,第1张

移动互联网时代,用户对于网页的打开速度要求越来越高。首屏作为直面用户的第一屏,其重要性不言而喻。优化用户体验更是我们前端开发非常需要 focus 的东西之一。

从用户的角度而言,当打开一个网页,往往关心的是从输入完网页地址后到最后展现完整页面这个过程需要的时间,这个时间越短,用户体验越好。所以作为网页的开发者,就从输入url到页面渲染呈现这个过程中去提升网页的性能。

所以输入URL后发生了什么呢?在浏览器中输入url会经历域名解析、建立TCP连接、发送http请求、资源解析等步骤。

http缓存优化是网页性能优化的重要一环,这一部分我会在后续笔记中做一个详细总结,所以本文暂不多做详细整理。本文主要从网页渲染过程、网页交互以及Vue应用优化三个角度对性能优化做一个小结。

首先谈谈拿到服务端资源后浏览器渲染的流程:

关键渲染路径是浏览器将 HTML、CSS、JavaScript 转换为在屏幕上呈现的像素内容所经历的一系列步骤。也就是我们刚刚提到的的的浏览器渲染流程。

为尽快完成首次渲染,我们需要最大限度减小以下三种可变因素:

首先,DOM 和 CSSOM 通常是并行构建的,所以 CSS 加载不会阻塞 DOM 的解析。

然而,由于 Render Tree 是依赖于 DOM Tree 和 CSSOM Tree 的,

所以他必须等待到 CSSOM Tree 构建完成,也就是 CSS 资源加载完成(或者 CSS 资源加载失败)后,才能开始渲染。因此,CSS 加载会阻塞 Dom 的渲染。

由此可见,对于 CSSOM 缩小、压缩以及缓存同样重要,我们可以从这方面考虑去优化。

当浏览器遇到 script 标记时,会阻止解析器继续操作,直到 CSSOM 构建完毕,JavaScript 才会运行并继续完成 DOM 构建过程。

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

回流(Reflow)

当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。现代浏览器会对频繁的回流或重绘操作进行优化:浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。

当你访问以下属性或方法时,浏览器会立刻清空队列:

因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。

避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。

避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中。

也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。

避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。

对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

图片懒加载在一些图片密集型的网站中运用比较多,通过图片懒加载可以让一些不可视的图片不去加载,避免一次性加载过多的图片导致请求阻塞(浏览器一般对同一域名下的并发请求的连接数有限制),这样就可以提高网站的加载速度,提高用户体验。

将页面中的img标签src指向一张小图片或者src为空,然后定义data-src(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src指向一张默认的图片,否则当src为空时也会向服务器发送一次请求。可以指向loading的地址。注意,图片要指定宽高。

当载入页面时,先把可视区域内的img标签的data-src属性值负给src,然后监听滚动事件,把用户即将看到的图片加载。这样便实现了懒加载。

事件委托其实就是利用JS事件冒泡机制把原本需要绑定在子元素的响应事件(click、keydown……)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。

优点:

例如有一个列表需要绑定点击事件,每一个列表项的点击都需要返回不同的结果。

传统写法:

传统方法会利用for循环遍历列表为每一个列表元素绑定点击事件,当列表中元素数量非常庞大时,需要绑定大量的点击事件,这种方式就会产生性能问题。这种情况下利用事件委托就能很好的解决这个问题。

改用事件委托:

输入搜索时,可以用防抖debounce等优化方式,减少http请求;

这里以滚动条事件举例:防抖函数 onscroll 结束时触发一次,延迟执行

节流函数:只允许一个函数在N秒内执行一次。滚动条调用接口时,可以用节流throttle等优化方式,减少http请求;

下面还是一个简单的滚动条事件节流函数:节流函数 onscroll 时,每隔一段时间触发一次,像水滴一样

参考链接: https://zhuanlan.zhihu.com/p/113864878?from_voters_page=true

展开全部 首先我们需要清楚,浏览器是如何读取选择器,以识别样式,并将相应的样式附于对应的HTML元素,达到美化页面的效果。Chris Coyier曾在《Efficiently Rendering CSS》一文中说过“浏览器读取你的选择器,遵循的原则是从选择器的右边到左边读取。换句话说,浏览器读取选择器的顺序是由右到左进行”。比如说: div.nav >ul li a 上面的实例来说,浏览器首先会尝试在你的HTML标签中寻找“a”元素,接着在匹配“li和ul”,最后在去匹配“div.nav”。这就是前成所主的“选择器从右到左的原则”。 选择器的最后一部分,也就是选择器的最右边(在这个例子中就是a[title]部分)部分被称为“关键选择器”,它将决定你的选择器的效率如何?是高还是低。 老版本的浏览器可以过滤掉不匹配的选择器,而直接匹配更高效的选择器。记得David Hyatt在《Writing efficient CSS for use in the Mozilla UI》说过:“这个关键选择器可以大大提高选择器的性能,少检查一个给定的元素规则,就可以更有效的将样式匹配给对应的HTML元素。”那么如何让关键选择器更有效,性能化更高呢?其实很简单,主要把握一点“越具体的关键选择器,其性能越高” 那么什么样类型的选择器,其性能高?什么样的类型的选择器性能低呢?下面我们就针对两个问题来展开具体的学习。 CSS选择器的效率 如果你阅读了本站的有关于选择器类型的介绍的话,你对选择器并不会感到陌生。就算你没读过,我想CSS选择器不会让我们觉得是新东西,比如我们常用的基本选择器“元素标签选择器div”、“id选择器#header”、“类选择器.class”,或者说我们很少见的伪类选择器“:focus”以及更复杂的css3选择器“:nth-child”等等。 选择器有一个固有的效率,我们来看Steve Souders给排的一个顺序: id选择器(#myid)类选择器(.myclassname)标签选择器(div,h1,p)相邻选择器(h1+p)子选择器(ul >li)后代选择器(li a)通配符选择器(*)属性选择器(a[rel="external"])伪类选择器(a:hover,li:nth-child) 上面九种选择器的效率是从高到低排下来的,基中ID选择器的效率是最高,而伪类选择器的效率则是最底。详细的介绍大家还可以点击Writing efficient CSS selectors。 综合上面的顺序,我们清楚的知道,id和类名用于关键选择器上效率是最高的,而CSS3的仿伪类和属性选择器,虽然使用方便,但其效率却是最低的。我们下面一起来看几个实例的对比: div #myid 效率要比下面的高: #myid div 第一种选择器比第二种选择器效率高,大家或许会问为什么?其实根据前面所介绍的我们就不难理解了,因为第一个选择器的“关键选择器”使用了 “ID选择器”,而第二个选择器的“关键选择器”使用的是“标签选择器”,对比下来,“ID选择器”效率高过“标签选择器”,所以说第一个选择器的效率要高于第二个选择器。 在类名或ID名前面加上标签也会致使选择器效率变低的,比如说: div #myid 上面两个选择的效率要高于下面的选择器: p#mydiv p.myclassname 来自Mozilla的几点建议 David在《Use efficient CSS selectors》中介绍了几种书写高效率的CSS选择器的方法,下面我将他们移到这里来让大家参考: 写道 1 避免普遍规则 2 不要在ID选择器前加标签名或类名 3 不要在类名选择器前加标签名 4 尽可能使用具体的类别 5 避免使用后代选择器 6 标签分类规则中不应该包含一个子选择器 7 子选择器的问题 8 借助相关继承关系 9 使用范围内的样式表 如果你不够清楚上面所讲的是什么,你可以点击这里,他会让你更容易了解这些规则。 我们应该怎么做 前面说“ID选择器”的效率是最高的,那么今天我们写样式,为了提高选择器的效率,是不是我们要在每一个文档的HTML元素中都加入ID名呢?我想这样的做法是没有的。对于一个有语义的代码编写和如何提高性能,以前他们之间如何的平衡?其实这个选择器的效率低一点,对于大多数网站来说并不会有太大的影响,但对于一个大型的网站,产生大量的流量这就会有差别了,也就很值得我们去对他进行优化。那么我们就很有必要的去了解他们是如何工作,比如说,一般情况下哪些选择器的使用效率更高。来看两个简单的例子: #myid 上面的选择器高于下面的: p#myid 后者的写法我发现还是有很多朋友这样写,但我不知道你为什么需要在ID前面加一个标签?难道你同一个页面会有多个相同的ID不成? 我们接下来在来看一个实例,用于列表上的,比如说我们制作导航菜单的: #nav a 高效于: #nav li a 上面只是介绍了两个常碰到的实例,在这里说这两个实例,主要目的是让你在今后的编写样式时,能注意这方面的的细节,从而加快你的代码效率。

直接给出结论: 1、css并不会阻塞DOM树的解析 2、css加载会阻塞DOM树渲染 3、css加载会阻塞后面js语句的执行 为了避免过长的白屏时间,我们应该尽可能的提高css加载速度,以下有几种优化方法: 1、使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间) 2、对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩) 3、合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号) 4、减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存) 关于DOMContentLoaded: 对于浏览器来说,页面加载主要有两个事件,一个是DOMContentLoaded,另一个是onLoad。而onLoad没什么好说的,就是等待页面的所有资源都加载完成才会触发,这些资源包括css、js、图片视频等。 1、如果页面中同时存在css和js,并且存在js在css后面,则DOMContentLoaded事件会在css加载完后才执行。 2、其他情况下,DOMContentLoaded都不会等待css加载,并且DOMContentLoaded事件也不会等待图片、视频等其他资源加载。 参考自:https://juejin.cn/post/6844903667733118983