前端性能优化的七大手段

前面的话

  本文将详细介绍前端性能优化的七大手段,包括减小请求数量、减少资源大小、优化网络链接、优化资源加载、减小重绘回流、使用性能更好的API和构建优化javascript

 

减小请求数量

【合并】css

  若是不进行文件合并,有以下3个隐患html

  一、文件与文件之间有插入的上行请求,增长了N-1个网络延迟前端

  二、受丢包问题影响更严重java

  三、通过代理服务器时可能会被断开webpack

  可是,文件合并自己也有本身的问题web

  一、首屏渲染问题算法

  二、缓存失效问题chrome

  因此,对于文件合并,有以下改进建议浏览器

  一、公共库合并

  二、不一样页面单独合并

【图片处理】

  一、雪碧图

  CSS雪碧图是之前很是流行的技术,把网站上的一些图片整合到一张单独的图片中,能够减小网站的HTTP请求数量,可是当整合图片比较大时,一次加载比较慢。随着字体图片、SVG图片的流行,该技术渐渐退出了历史舞台

  二、Base64

  将图片的内容以Base64格式内嵌到HTML中,能够减小HTTP请求数量。可是,因为Base64编码用8位字符表示信息中的6个位,因此编码后大小大约比原始值扩大了 33%

  三、使用字体图标来代替图片

【减小重定向】

  尽可能避免使用重定向,当页面发生了重定向,就会延迟整个HTML文档的传输。在HTML文档到达以前,页面中不会呈现任何东西,也没有任何组件会被下载,下降了用户体验

  若是必定要使用重定向,如http重定向到https,要使用301永久重定向,而不是302临时重定向。由于,若是使用302,则每一次访问http,都会被重定向到https的页面。而永久重定向,在第一次从http重定向到https以后 ,每次访问http,会直接返回https的页面

【使用缓存】

  使用cach-control或expires这类强缓存时,缓存不过时的状况下,不向服务器发送请求。强缓存过时时,会使用last-modified或etag这类协商缓存,向服务器发送请求,若是资源没有变化,则服务器返回304响应,浏览器继续从本地缓存加载资源;若是资源更新了,则服务器将更新后的资源发送到浏览器,并返回200响应

【不使用CSS @import】

  CSS的@import会形成额外的请求

【避免使用空的src和href】

  a标签设置空的href,会重定向到当前的页面地址

  form设置空的method,会提交表单到当前的页面地址

 

减少资源大小

【压缩】

  一、HTML压缩

  HTML代码压缩就是压缩在文本文件中有意义,可是在HTML中不显示的字符,包括空格,制表符,换行符等

  二、CSS压缩

  CSS压缩包括无效代码删除与CSS语义合并

  三、JS压缩与混乱

  JS压缩与混乱包括无效字符及注释的删除、代码语义的缩减和优化、下降代码可读性,实现代码保护

  四、图片压缩

  针对真实图片状况,舍弃一些相对可有可无的色彩信息

【webp】

  在安卓下可使用webp格式的图片,它具备更优的图像数据压缩算法,能带来更小的图片体积,同等画面质量下,体积比jpg、png少了25%以上,并且同时具有了无损和有损的压缩模式、Alpha 透明以及动画的特性

【开启gzip】

  HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点经常使用GZIP压缩技术来让用户感觉更快的速度。这通常是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来。通常对纯文本内容可压缩到原大小的40%

 

优化网络链接

【使用CDN】

  CDN全称是Content Delivery Network,即内容分发网络,它可以实时地根据网络流量和各节点的链接、负载情况以及到用户的距离和响应时间等综合信息将用户的请求从新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的情况,提升用户访问网站的响应速度

【使用DNS预解析】

  当浏览器访问一个域名的时候,须要解析一次DNS,得到对应域名的ip地址。在解析过程当中,按照浏览器缓存系统缓存路由器缓存ISP(运营商)DNS缓存根域名服务器顶级域名服务器主域名服务器的顺序,逐步读取缓存,直到拿到IP地址

  DNS Prefetch,即DNS预解析就是根据浏览器定义的规则,提早解析以后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提升网站的访问速度

  方法是在 head 标签里面写上几个 link 标签

<link rel="dns-prefecth" href="https://www.google.com">
<link rel="dns-prefecth" href="https://www.google-analytics.com">

  对以上几个网站提早解析 DNS,因为它是并行的,不会堵塞页面渲染,这样能够缩短资源加载的时间

【并行链接】

  因为在HTTP1.1协议下,chrome每一个域名的最大并发数是6个。使用多个域名,能够增长并发数

【持久链接】

  使用keep-alive或presistent来创建持久链接,持久链接下降了时延和链接创建的开销,将链接保持在已调谐状态,并且减小了打开链接的潜在数量

【管道化链接】

  在HTTP2协议中,能够开启管道化链接,即单条链接的多路复用,每条链接中并发传输多个资源,这里就不须要添加域名来增长并发数了

 

优化资源加载

【资源加载位置】

  经过优化资源加载位置,更改资源加载时机,使尽量快地展现出页面内容,尽量快地使功能可用

  一、CSS文件放在head中,先外链,后本页

  二、JS文件放在body底部,先外链,后本页

  三、处理页面、处理页面布局的JS文件放在head中,如babel-polyfill.js文件、flexible.js文件

  四、body中间尽可能不写style标签和script标签

【资源加载时机】

  一、异步script标签

  defer:  异步加载,在HTML解析完成后执行。defer的实际效果与将代码放在body底部相似

  async: 异步加载,加载完成后当即执行

  二、模块按需加载

  在SPA等业务逻辑比较复杂的系统中,须要根据路由来加载当前页面须要的业务模块

  按需加载,是一种很好的优化网页或应用的方式。这种方式其实是先把代码在一些逻辑断点处分离开,而后在一些代码块中完成某些操做后,当即引用或即将引用另一些新的代码块。这样加快了应用的初始加载速度,减轻了它的整体体积,由于某些代码块可能永远不会被加载

  webpack 提供了两个相似的技术,优先选择的方式是使用符合 ECMAScript 提案 的 import() 语法。第二种则是使用 webpack 特定的 require.ensure

  三、使用资源预加载preload和资源预读取prefetch

  preload让浏览器提早加载指定资源,须要执行时再执行,能够加速本页面的加载速度

  prefetch告诉浏览器加载下一页面可能会用到的资源,能够加速下一个页面的加载速度

  四、资源懒加载与资源预加载

  资源延迟加载也称为懒加载,延迟加载资源或符合某些条件时才加载某些资源

  资源预加载是提早加载用户所需的资源,保证良好的用户体验

  资源懒加载和资源预加载都是一种错峰操做,在浏览器忙碌的时候不作操做,浏览器空间时,再加载资源,优化了网络性能

  

减小重绘回流

【样式设置】

  一、避免使用层级较深的选择器,或其余一些复杂的选择器,以提升CSS渲染效率

  二、避免使用CSS表达式,CSS表达式是动态设置CSS属性的强大但危险方法,它的问题就在于计算频率很快。不只仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要从新计算一次

  三、元素适当地定义高度或最小高度,不然元素的动态内容载入时,会出现页面元素的晃动或位置,形成回流

  四、给图片设置尺寸。若是图片不设置尺寸,首次载入时,占据空间会从0到彻底出现,上下左右均可能位移,发生回流

  五、不要使用table布局,由于一个小改动可能会形成整个table从新布局。并且table渲染一般要3倍于同等元素时间

  六、可以使用CSS实现的效果,尽可能使用CSS而不使用JS实现

【渲染层】

  一、此外,将须要屡次重绘的元素独立为render layer渲染层,如设置absolute,能够减小重绘范围

  二、对于一些进行动画的元素,使用硬件渲染,从而避免重绘和回流

【DOM优化】

  一、缓存DOM

const div = document.getElementById('div')

  因为查询DOM比较耗时,在同一个节点无需屡次查询的状况下,能够缓存DOM

  二、减小DOM深度及DOM数量

  HTML 中标签元素越多,标签的层级越深,浏览器解析DOM并绘制到浏览器中所花的时间就越长,因此应尽量保持 DOM 元素简洁和层级较少。

  三、批量操做DOM

  因为DOM操做比较耗时,且可能会形成回流,所以要避免频繁操做DOM,能够批量操做DOM,先用字符串拼接完毕,再用innerHTML更新DOM

  四、批量操做CSS样式

  经过切换class或者使用元素的style.csstext属性去批量操做元素样式

  五、在内存中操做DOM

  使用DocumentFragment对象,让DOM操做发生在内存中,而不是页面上

  六、DOM元素离线更新

  对DOM进行相关操做时,例、appendChild等均可以使用Document Fragment对象进行离线操做,带元素“组装”完成后再一次插入页面,或者使用display:none 对元素隐藏,在元素“消失”后进行相关操做

  七、DOM读写分离

  浏览器具备惰性渲染机制,链接屡次修改DOM可能只触发浏览器的一次渲染。而若是修改DOM后,当即读取DOM。为了保证读取到正确的DOM值,会触发浏览器的一次渲染。所以,修改DOM的操做要与访问DOM分开进行

  八、事件代理

  事件代理是指将事件监听器注册在父级元素上,因为子元素的事件会经过事件冒泡的方式向上传播到父节点,所以,能够由父节点的监听函数统一处理多个子元素的事件

  利用事件代理,能够减小内存使用,提升性能及下降代码复杂度

  九、防抖和节流

  使用函数节流(throttle)或函数去抖(debounce),限制某一个方法的频繁触发

  十、及时清理环境

  及时消除对象引用,清除定时器,清除事件监听器,建立最小做用域变量,能够及时回收内存

 

性能更好的API

  一、用对选择器

  选择器的性能排序以下所示,尽可能选择性能更好的选择器

复制代码
id选择器(#myid)
类选择器(.myclassname)
标签选择器(div,h1,p)
相邻选择器(h1+p)
子选择器(ul > li)
后代选择器(li a)
通配符选择器(*)
属性选择器(a[rel="external"])
伪类选择器(a:hover,li:nth-child)
复制代码

  二、使用requestAnimationFrame来替代setTimeout和setInterval

  但愿在每一帧刚开始的时候对页面进行更改,目前只有使用 requestAnimationFrame 可以保证这一点。使用 setTimeout 或者 setInterval 来触发更新页面的函数,该函数可能在一帧的中间或者结束的时间点上调用,进而致使该帧后面须要进行的事情没有完成,引起丢帧

  三、使用IntersectionObserver来实现图片可视区域的懒加载

  传统的作法中,须要使用scroll事件,并调用getBoundingClientRect方法,来实现可视区域的判断,即便使用了函数节流,也会形成页面回流。使用IntersectionObserver,则没有上述问题

  四、使用web worker

  客户端javascript一个基本的特性是单线程:好比,浏览器没法同时运行两个事件处理程序,它也没法在一个事件处理程序运行的时候触发一个计时器。Web Worker是HTML5提供的一个javascript多线程解决方案,能够将一些大计算量的代码交由web Worker运行,从而避免阻塞用户界面,在执行复杂计算和数据处理时,这个API很是有用

  可是,使用一些新的API的同时,也要注意其浏览器兼容性

 

webpack优化

【打包公共代码】

  使用CommonsChunkPlugin插件,将公共模块拆出来,最终合成的文件可以在最开始的时候加载一次,便存到缓存中供后续使用。这会带来速度上的提高,由于浏览器会迅速将公共的代码从缓存中取出来,而不是每次访问一个新页面时,再去加载一个更大的文件

  webpack 4 将移除 CommonsChunkPlugin, 取而代之的是两个新的配置项 optimization.splitChunks 和 optimization.runtimeChunk

  经过设置 optimization.splitChunks.chunks: "all" 来启动默认的代码分割配置项

【动态导入和按需加载】

  webpack提供了两种技术经过模块的内联函数调用来分离代码,优先选择的方式是,使用符合 ECMAScript 提案 的 import() 语法。第二种,则是使用 webpack 特定的 require.ensure

【剔除无用代码】

  tree shaking 是一个术语,一般用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。这个术语和概念其实是兴起于 ES2015 模块打包工具 rollup

  JS的tree shaking主要经过uglifyjs插件来完成,CSS的tree shaking主要经过purify CSS来实现的

【长缓存优化】

  一、将hash替换为chunkhash,这样当chunk不变时,缓存依然有效

  二、使用Name而不是id

  每一个 module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变

  下面来使用两个插件解决这个问题。第一个插件是 NamedModulesPlugin,将使用模块的路径,而不是数字标识符。虽然此插件有助于在开发过程当中输出结果的可读性,然而执行时间会长一些。第二个选择是使用 HashedModuleIdsPlugin,推荐用于生产环境构建

【公用代码内联】

  使用html-webpack-inline-chunk-plugin插件将mainfest.js内联到html文件中

 

原文地址:https://www.cnblogs.com/xiaohuochai/p/9178390.html

相关文章
相关标签/搜索