前端面经 前端优化
文章目录
- 前端面经 前端优化
- HTTP/2 Web优化最佳实践
- DNS与解析
- 如何使用
- CDN分发
- 缓存策略
- 页面渲染优化
- 避免CSS、JS阻塞
- CSS阻塞
- JS的阻塞
- 改变JS阻塞的方式
- 使用字体图标iconfont代替图片图标
- 降低CSS选择器的复杂性
- 减少重绘和回流
- 如何避免
- 图片资源优化
- Webpack优化
降低请求量:合并资源,减少 HTTP 请求数,minify / gzip 压缩,webP,lazyLoad。
加快请求速度:预解析 DNS,减少域名数,并行加载,CDN 分发。
缓存:HTTP 协议缓存请求,离线缓存 manifest,离线数据缓存 localStorage。
渲染:JS/CSS 优化,加载顺序,服务端渲染,pipeline。
HTTP/2 Web优化最佳实践
DNS与解析
DNS 预读取是一项使浏览器主动去执行域名解析的功能,其范围包括文档的所有链接,无论是图片的,CSS 的,还是 JavaScript 等其他用户能够点击的 URL,减少用户点击链接时的延迟。
作用:作用:根据浏览器定义的规则,提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提高网站的访问速度
如何使用
- 打开和关闭DNS预解析
希望在HTTPS
页面开启自动解析功能,添加如下标记
也可以通过在服务器端发送<meta http-equiv="x-dns-prefetch-control" content="on">
X-DNS-Prefetch-Control
报头 - 自动解析
Chromium会自动解析href
属性(a标签),该行为与用户浏览网页是并行的。但为了确保安全,HTTPS页面不会自动解析Chromium不使用浏览器的网络堆栈,直接使用操作系统的缓存。通过8个异步线程执行预解析,每个线程处理一个队列,来等待域名的响应,最终操作系统会响应一个DNS结果给线程,然后线程丢弃它,等待下一个预解析请求。
- 手动添加解析
<link rel="dns-prefetch" href="http://www.google.com">
- 在浏览器中设置
一般来说并不需要去管理预读取,但是可能会有用户希望关闭预读取功能。这时只需要设置network.dns.disablePrefetch preference
值为true
就可以了
默认情况下,通过 HTTPS 加载的页面上内嵌链接的域名并不会执行预加载。在 Firefox 浏览器中,可以通过设置network.dns.disablePrefetchFromHTTPS
值为false
来改变这一默认行为。
CDN分发
CDN这个技术其实说起来并不复杂,最初的核心理念,就是将内容缓存在终端用户附近。
内容源不是远么?那么,我们就在靠近用户的地方,建一个缓存服务器,把远端的内容,复制一份,放在这里,不就OK了?
具体来说,CDN就是采用更多的缓存服务器(CDN边缘节点),布放在用户访问相对集中的地区或网络中。当用户访问网站时,利用全局负载技术,将用户的访问指向距离最近的缓存服务器上,由缓存服务器响应用户请求。
总结:
我们都知道,当服务器离用户越远时,延迟越高。CDN 就是为了解决这一问题,在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。
缓存策略
参考文章:https://blog.csdn.net/qq_56303170/article/details/127680487
页面渲染优化
Webkit 渲染引擎流程:
- 处理 HTML 并构建 DOM 树
- 处理 CSS 构建 CSS 规则树(CSSOM)
- 接着JS 会通过 DOM Api 和 CSSOM Api 来操作 DOM Tree 和 CSS Rule Tree 将 DOM Tree 和 CSSOM Tree 合成一颗渲染树 Render Tree。
- 根据渲染树来布局,计算每个节点的位置
- 调用 GPU 绘制,合成图层,显示在屏幕上
避免CSS、JS阻塞
CSS阻塞
默认情况下,CSS是阻塞的资源。浏览器在构建CSSOM的过程中,不会渲染任何已处理的内容,即便DOM已经解析完毕了
只有当我们开始解析HTML后,解析到link标签或者style标签时,CSS才登场,CSSDOM的构建才开始。 很多时候,DOM不得不等待CSSOM,因此总结:
CSS是阻塞渲染的资源。需要将它尽早、尽快下载到客户端,以便缩短首次渲染的时间。尽早(将CSS放在head标签中)和尽快(启用CDN实现静态资源加载速度的优化)
JS的阻塞
JS的作用在于修改,本质上都是对DOM和CSSOM进行修改。因此JS的执行会阻止CSSOM,在我们不做显示声明的情况下,它也会阻塞DOM
JS 引擎是独立于渲染引擎存在的。我们的 JS 代码在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标签时,它会暂停渲染过程,将控制权交给 JS 引擎。JS 引擎对内联的 JS 代码会直接执行,对外部 JS 文件还要先获取到脚本、再进行执行。等 JS 引擎运行完毕,浏览器又会把控制权还给渲染引擎,继续 CSSOM 和 DOM 的构建。 因此与其说是 JS 把 CSS 和 HTML 阻塞了,不如说是 JS 引擎抢走了渲染引擎的控制权。
实际使用时,可以遵循下面3个原则:
- CSS资源优于JavaScript资源引入
- JS应尽量少影响DOM的构建
改变JS阻塞的方式
defer(延缓)模式
defer
方式加载script
,不会阻塞HTML
,等到DOM
生成完毕且script
加载完毕再执行JS
<script defer></script>
async(异步)模式
async
属性表示异步执行引入的 JS
,加载时不会阻塞 HTML
解析,但是加载完成后立马执行,此时仍然会阻塞 load 事件
<script async></script>
从应用的角度来说,一般当我们的脚本与 DOM 元素和其它脚本之间的依赖关系不强时,我们会选用 async
;当脚本依赖于 DOM 元素和其它脚本的执行结果时,我们会选用defer
。
使用字体图标iconfont代替图片图标
字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。并且字体图标是矢量图,不会失真。还有一个优点是生成的文件特别小。
降低CSS选择器的复杂性
浏览器读取选择器,遵循的原则是从选择器的右边到左边:
#block .text p {
color: red;
}
- 查找所有 P 元素。
- 查找结果 1 中的元素是否有类名为 text 的父元素
- 查找结果 2 中的元素是否有 id 为 block 的父元素
总结:
- 减少嵌套。后代选择器的开销是最高的,因此我们应该尽量将选择器的深度降到最低(最高不要超过三层),尽可能使用类来关联每一个标签元素
- 关注可以通过继承实现的属性,避免重复匹配重复定义
- 尽量使用高优先级的选择器,例如 ID 和类选择器。
- 避免使用通配符,只对需要用到的元素进行选择
减少重绘和回流
重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘
回流:当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
回流必将引起重绘,重绘不一定会引起回流,回流比重绘的代价更高
如何避免
CSS:
- 避免使用
table
布局 - 尽可能在DOM树的最末端改变
class
- 避免设置多层内联样式
- 将动画效果应用到
position
属性为absolute
或fixed
的元素上 - 避免使用CSS表达式(例如:
calc()
)
JS:
- 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
- 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
- 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
图片资源优化
-
使用雪碧图:
雪碧图的作用就是减少请求数,而且多张图片合在一起后的体积会少于多张图片的体积和,这也是比较通用的图片压缩方案 -
降低图片质量:
压缩方法有两种,一是通过在线网站进行压缩,二是通过 webpack 插件 image-webpack-loader。 -
图片懒加载
在页面中,先不给图片设置路径,只有当图片出现在浏览器的可视区域时,才去加载真正的图片,这就时延迟加载。对于图片较多的网站来说,一次性加载全部的图片,会对用户体验造成很大的影响
Webpack优化
参考文章:https://blog.csdn.net/qq_56303170/article/details/126452385