前端性能优化
浏览器渲染机制
Html解析成DOM树,Css解析成CSS树,将DOM树与CSSDOM规则树合并在一起生成Render树,遍历渲染树开始布局,计算每个节点的位置大小信息,将渲染树每个节点绘制到屏幕
阻塞渲染
当浏览器遇到一个script标记时,DOM构建将暂停,直至脚本完成执行,然后继续构建DOM。每次去执行JavaScript脚本都会严重的阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建
1.link,script放置位置
浏览器下载脚本时,会阻塞其他资源并行下载,即使是来自不同域名的资源。因此,最好将脚本放在底部,以提高页面加载速度。link的css样式放在head中,引入的包放在自己的js之前。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <link rel="stylesheet" type="text/css" href="D:/deng/project/myreports-project/first/index.css" /> </head> <body> <div id='#app'></div> <script src='./index.js'></script> </body> </html>
一、HTTP
从输入URL到浏览器显示页面发生了什么
1.减少域名使用
浏览器获取资源需要做DNS解析,建立了TCP/IP的连接,所以项目中存在很多域名时会直接导致加载缓慢。
2.减少HTTP请求数
将图片的图标合并成一个文件,利用background-position来调整位置
行内图片(Base64编码),使用Data URI scheme将图片嵌入HTML或者CSS中;或者将CSS、JS、图片直接嵌入HTML中,会增加文件大小,也可能产生浏览器兼容及其他性能问
合并JS/CSS文件。服务器端(CDN)自动合并,基于Node.js的文件合并工具,通过把所有脚本放在一个文件中的方式来减少请求数
3.减少DNS查询
浏览器需要查询域名对应的ip的地址,一般需要耗费20-120毫秒时间。DNS查询完成之前,浏览器无法从服务器下载任何数据,但是可以缓存
IE缓存30分钟,可以通过注册表中DnsCacheTimeout项设置;
Firefox缓存1分钟,通过network.dnsCacheExpiration配置;
1
2
4.缓存
前端缓存最佳实践
在介绍缓存的时候,我们习惯将缓存分为强缓存和协商缓存两种。两者的主要区别是使用本地缓存的时候,是否需要向服务器验证本地缓存是否依旧有效。顾名思义,协商缓存,就是需要和服务器进行协商,最终确定是否使用本地缓存。
5.延迟加载
页面初始加载时哪些内容是绝对必需的?不是必须展示的资源都可以延迟加载
非首屏使用的数据、样式、脚本、图片等;
用户交互时才会显示的内容。
6.预加载
预先加载利用浏览器空闲时间请求将来要使用的资源,以便用户访问下一页面时更快地响应。根据用户行为预判用户去向,预载相关资源。比如search.yahoo.com开始输入时会有额外的资源加载。Chrome 等浏览器的地址栏也有类似的机制。
7.减少DOM数量和层级
复杂的页面不仅下载的字节更多,JavaScript DOM操作也更慢。例如,同是添加一个事件处理器,500个元素和5000个元素的页面速度上会有很大区别。而且层级很深对SEO也不友好,结构变化时,回流时更需要时间。
8.减少使用iframe
用iframe可以把一个HTML文档插入到父文档里,重要的是明白iframe是如何工作的并高效地使用它。
加载代价昂贵,即使是空的页面;
阻塞页面 load 事件触发;
不利于SEO
9.内容划分到不同域名
浏览器一般会限制每个域的并行线程(一般为6个,甚至更少),使用不同的域名可以最大化下载线程,但注意保持在2-4个域名内,以避免DNS查询损耗。
二、服务器
1.CDN加速
CDN的全称Content Delivery Network,(缩写:CDN)即内容分发网络。
CDN是一个经策略性部署的整体系统,从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均而产生的用户访问网站响应速度慢的根本原因。
CDN目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,解决 Internet 网络拥塞状况,提高用户访问网站的响应速度。
一般的公司不可能在每个城市地区都有服务器,那么用户一次完整的请求要经过的历程将路漫漫其修远兮
2.缓存
前端缓存最佳实践
HTML:使用协商缓存。
CSS&JS&图片:使用强缓存,文件命名带上hash值。
1
2
3.GZIP压缩
Gzip压缩通常可以减少70%的响应大小,对某些文件更可能高达90%,比Deflate更高效。主流 Web 服务器都有相应模块,而且绝大多数浏览器支持gzip解码。所以,应该对HTML、CSS、JS、XML、JSON等文本类型的内容启用压缩,Nginx能直接读取gzip文件。
注意!!! 图片和 PDF 文件不要使用 gzip。它们本身已经压缩过,再使用 gzip 压缩不仅浪费 CPU 资源,而且还可能增加文件体积。
1
4.ajax尽量使用GET方法
浏览器执行XMLHttpRequest POST请求时分成两步,先发送Http Header,再发送data。而GET只使用一个TCP数据包(Http Header与data)发送数据,所以首选GET方法。根据HTTP规范,GET用于获取数据,POST则用于向服务器发送数据,所以Ajax请求数据时使用GET更符合规范。
5.负载均衡
Load balancing,即负载均衡,是一种计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。
6.提高带宽
最直接有效的方法就是给服务器升级,提高带宽与内存,既能抵挡cc攻击,又能让并发变高。
三、性能检测工具
1.谷歌插件——Page Speed
我们只需要打开待测试的网页,然后点击Page Speed里的 Start analyzing按钮,它就会自动帮我们测试网络传输性能了
2.谷歌录制
然后结束后能查看当前网页的nodes,listener,deep,可以分析出是否存在内存溢出风险,性能优化需要的修改。
四、Css
1.favicon
请不要忘记为你的网站加上它,它就好像是你的网站的 ID。无论你有没有 favicon.ico ,用户的浏览器依然会请求它。如果你忘记加上这个档案,你的网站就会返回 404 Not Found,这会让浏览器面红。。。所以你要小心一点,避免给予用户负面的第一印象。要解决这个问题,你可以透过?Favicon Generator?生成 favicon 和 manifest 档案。
2.把link放在中
把样式表放在中可以让页面渐进渲染,尽早呈现视觉反馈,给用户加载速度很快的感觉。这对内容比较多的页面尤为重要,用户可以先查看已经下载渲染的内容,而不是盯着白屏等待。
3.避免使用CSS表达式
CSS表达式,如下面这个例子:
background-color:expression((new Date().getHours()%2?"#B8D4FF":"#F08A00"));
1
这个表示是为了实现背景颜色每2个小时变化一次;这种会导致性能下降。不过应该多数开发人员比较少使用CSS表达式。这里就一笔带过就好了。
4.使用替代@import
对于IE某些版本,@import的行为和放在页面底部一样。所以,不要用它。
五、JavaScript
1.把脚本放在页面底部
浏览器下载脚本时,会阻塞其他资源并行下载,即使是来自不同域名的资源。因此,最好将脚本放在底部,以提高页面加载速度。
2.减少DOM操作
JavaScript 操作 DOM 很慢,尤其是 DOM 节点很多时。当然现在前端框架都是使用虚拟DOM,很少直接操作DOM了。
3.使用高效的事件处理
减少绑定事件监听的节点,如通过事件委托,就是子级交互都是一个,不如父级来添加这个事件;尽早处理事件,在DOMContentLoaded即可进行,不用等到load以后。
六、React
1.shouldComponentUpdate避免重复渲染
react提供这个钩子函数来优化不必要的渲染,可以自定义渲染时机
class CounterButton extends React.Component { constructor(props) { super(props); this.state = {count: 1}; } shouldComponentUpdate(nextProps, nextState) { if (this.props.color !== nextProps.color) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } }
2.bind函数
(1)constructor绑定
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //构造函数中绑定
}
//然后可以
<p onClick={this.handleClick}>
(2)使用时绑定
<p onClick={this.handleClick.bind(this)}>
1
(3)使用箭头函数
<p onClick={()=>this.handleClick()}>
1
使用第一种,第二种每次render都会执行,第三种每次render都会生成箭头函数。
3.不要滥用props
props的更改会导致子组件更新,props尽量只传需要的数据,避免多余的更新,尽量避免使用{…props}
4.Key的绑定
为list添加key,能帮助react在更新时准确找到要更新的部分。
5.组件按需引入
import { Button } from 'antd'
1
6.打包压缩代码
使用webpack打包压缩代码。
7.路由拆分
可以将路由打包拆分,将会生成多个js文件,在路由加载到的时候才加载该js文件,像umijs就自带路由系统,能配置路由是否按需加载。
七、Vue
1.路由按需加载
可以将路由打包拆分,将会生成多个js文件,在路由加载到的时候才加载该js文件,具体实现方案的话,如下:
1、基于require.js来实现引入模块的方式(比较老)
let routes = [ {path: '/home', component: resolve => require(['./components/Home.vue'], resolve), children:[ {path: '/detail', component: resolve => require(['./components/Detail.vue'], resolve)} ]} ]
2、es6模块化的拆分形式
let routes = [ {path: '/home', component: () => import('./components/Home.vue'), children:[ {path: '/detail', component: () => import('./components/Detail.vue'), resolve)} ]} ]
2.组件按需加载
像这种全局引入会导致最终打包文件过大,首次加载时间非常长
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
3.v-if 和 v-show选择调用
v-show和v-if的区别是:v-if是懒加载,当状态为true时才会加载,并且为false时不会占用布局空间;v-show是无论状态是true或者是false,都会进行渲染,并对布局占据空间对于在项目中,需要频繁调用,不需要权限的显示隐藏,可以选择使用v-show,可以减少系统的切换开销。
4.不要滥用props
props的更改会导致子组件更新,props尽量只传需要的数据,避免多余的更新,尽量避免使用{…props}
5.Key的绑定
为list添加key,能帮助react在更新时准确找到要更新的部分。
6.打包
1、sourcemap 一个可以从中查看源码的文件,但是在线上环境是没必要的,这个就可以关闭
2、别名的使用,使用别名比使用相对路径在服务器上查找文件更快
module.exports = { resolve: { extensions: ['.js', '.vue', '.json'], // 使用这些后缀的文件时就可不写扩展名 alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } } }
3、assetsPublicPath设置为/时能被nginx代理识别,但是无法被文件系统识别,但是访问速度比设置成./时快
module.exports = { build:{ assetsPublicPath: '/', } }
4、js文件压缩,webpack使用uglifyjs-webpack-plugin插件压缩js代码
八、图片资源
1.避免图片src为空
虽然src属性为空字符串,但浏览器仍然会向服务器发起一个HTTP请求:
IE 向页面所在的目录发送请求;
Safari、Chrome、Firefox向页面本身发送请求;
Opera不执行任何操作。
空src产生请求的后果不容小觑:
给服务器造成意外的流量负担,尤其时日 PV 较大时;
浪费服务器计算资源;
可能产生报错。
2.雪碧图(Sprite)
将很多图片图标整合到一张图片,通过background-position来控制显示位置。
3.使用字体图标(iconfont)
不论是压缩后的图片,还是雪碧图,终归还是图片,只要是图片,就还是会占用大量网络传输资源。字体图标是通过css实现的,而且可以通过font-size来改变尺寸,通过color来改变颜色,比图片资源更灵活。
4.不要在HTML中缩放图片
不要使用的width、height缩放图片,如果用到小图片,就使用相应大小的图片。如果需要那么图片本身(mycat.jpg)应该是100x100px的,而不是去缩小500x500px的图片。现在很多云存储支持图片裁剪,能自定义很多种的裁剪方式。
5.使用WebP
WebP格式,是谷歌公司开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。Facebook、Ebay等知名网站已经开始测试并使用WebP格式。
6.图片懒加载
一张图片就是一个标签,浏览器是否发起请求图片是根据的src属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。