抛出一个问题,从输入
url
地址栏到全部内容显示到界面上作了哪些事?css
DNS
服务器请求解析该 URL 中的域名所对应的 IP
地址;TCP
链接(三次握手);URL
中域名后面部分对应的文件)的HTTP
请求,该请求报文做为 TCP
三次握手的第三个报文的数据发送给服务器;html
文本并显示内容;TCP
链接(四次挥手);上面这个问题是一个面试官很是喜欢问的问题,咱们下面把这6个步骤分解,逐步细谈优化。html
DNS
解析DNS`解析:将域名解析为ip地址 ,由上往下匹配,只要命中便中止前端
- 走缓存
- 浏览器DNS缓存
- 本机DNS缓存
- 路由器DNS缓存
- 网络运营商服务器DNS缓存 (80%的DNS解析在这完成的)
- 递归查询
复制代码
优化策略:尽可能容许使用浏览器的缓存,能给咱们节省大量时间。java
TCP
的三次握手SYN (同步序列编号)ACK(确认字符)react
第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等 待Server确认。webpack
第二次握手:Server收到数据包后由标志位SYN=1知道Client请求创建链接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认链接请求,Server进入SYN_RCVD状态。es6
第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,若是正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,若是正确则链接创建成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间能够开始传输数据了。web
优化策略:面试
HTTP
协议通讯最耗费时间的是创建TCP
链接的过程,那咱们就可使用HTTP Keep-Alive
,在HTTP
早期,每一个HTTP
请求都要求打开一个TCP socket
链接,而且使用一次以后就断开这个TCP
链接。 使用keep-alive
能够改善这种状态,即在一次TCP链接中能够持续发送多份数据而不会断开链接。经过使用keep-alive
机制,能够减小TCP
链接创建次数,也意味着能够减小TIME_WAIT
状态链接,以此提升性能和提升http
服务器的吞吐率(更少的tcp
链接意味着更少的系统内核调用keep-alive
并非免费的午饭,长时间的TCP
链接容易致使系统资源无效占用。配置不当的keep-alive
,有时比重复利用链接带来的损失还更大。因此,正确地设置keep-alive timeout
时间很是重要。(这个keep-alive_timout
时间值意味着:一个http
产生的tcp
链接在传送完最后一个响应后,还须要hold
住keepalive_timeout
秒后,才开始关闭这个链接),若是想更详细了解能够看这篇文章keep-alve性能优化的测试结果webScoket
通讯协议,仅一次TCP
握手就一直保持链接,并且他对二进制数据的传输有更好的支持,能够应用于即时通讯,海量高并发场景。webSocket的原理以及详解HTTP
请求次数,每次HTTP
请求都会有请求头,返回响应都会有响应头,屡次请求不只浪费时间并且会让网络传输不少无效的资源,使用前端模块化技术 AMD CMD commonJS ES6等模块化方案
将多个文件压缩打包成一个,固然也不能都放在一个文件中,由于这样传输起来可能会很慢,权衡取一个中间值cookie
去辨识用户的多种情况时,使用session
替代,把数据储存在服务器端或者服务器端的数据库中,这样只须要一个cookie
传输,节省大量的无效传输,并且储存的数据能够是永久无线大的。html
文件DOM
树css
标记,调用css解析器将其解析CSSOM
树link
阻塞 - 为了解决闪屏,全部解决闪屏的样式style
非阻塞,与闪屏的样式不相关的DOM
树和CSSOM
树结合在一块儿,造成render
树script
标签,阻塞,调用js
解析器解析js
代码,可能会修改DOM
树,也可能会修改CSSOM
树DOM
树和CSSOM
树结合在一块儿,造成render
树layout
布局 render
渲染(重排重绘)script
标签的属性
性能优化策略:算法
link
引入,不须要的使用style
标签(具体是否须要阻塞看业务场景)webpack4
中也要配置图片压缩,能极大压缩图片大小,对于新版本浏览器可使用webp格式图片
webP详解,图片优化对性能提高最大。webpack4
配置 代码分割,提取公共代码成单独模块。方便缓存/*
runtimeChunk 设置为 true, webpack 就会把 chunk 文件名所有存到一个单独的 chunk 中,
这样更新一个文件只会影响到它所在的 chunk 和 runtimeChunk,避免了引用这个 chunk 的文件也发生改变。
*/
runtimeChunk: true,
splitChunks: {
chunks: 'all' // 默认 entry 的 chunk 不会被拆分, 配置成 all, 就能够了
}
}
//由于是单入口文件配置,因此没有考虑多入口的状况,多入口是应该分别进行处理。
复制代码
对于须要事件驱动的webpack4
配置懒加载的,能够看这篇webpack4优化教程,写得很是全面
一些原生javaScript
的DOM
操做等优化会在下面总结
TCP
的四次挥手,断开链接RAIL
Responce
响应,研究代表,100ms内对用户的输入操做进行响应,一般会被人类认为是当即响应。时间再长,操做与反应之间的链接就会中断,人们就会以为它的操做有延迟。例如:当用户点击一个按钮,若是100ms内给出响应,那么用户就会以为响应很及时,不会察觉到丝毫延迟感。Animaton
现现在大多数设备的屏幕刷新频率是60Hz,也就是每秒钟屏幕刷新60次;所以网页动画的运行速度只要达到60FPS,咱们就会以为动画很流畅。Idle
RAIL规定,空闲周期内运行的任务不得超过50ms,固然不止RAIL规定,W3C性能工做组的Longtasks标准也规定了超过50毫秒的任务属于长任务,那么50ms这个数字是怎么得来的呢?浏览器是单线程的,这意味着同一时间主线程只能处理一个任务,若是一个任务执行时间过长,浏览器则没法执行其余任务,用户会感受到浏览器被卡死了,由于他的输入得不到任何响应。为了达到100ms内给出响应,将空闲周期执行的任务限制为50ms意味着,即便用户的输入行为发生在空闲任务刚开始执行,浏览器仍有剩余的50ms时间用来响应用户输入,而不会产生用户可察觉的延迟。Load
若是不能在1秒钟内加载网页并让用户看到内容,用户的注意力就会分散。用户会以为他要作的事情被打断,若是10秒钟还打不开网页,用户会感到失望,会放弃他们想作的事,之后他们或许都不会再回来。如何使网页更丝滑?
使用requestAnimationFrame
避免FSL
先执行JS
,而后在JS
中修改了样式从而致使样式计算,而后样式的改动触发了布局、绘制、合成。但JavaScript
能够强制浏览器将布局提早执行,这就叫 强制同步布局FSL
。
//读取offsetWidth的值会致使重绘
const newWidth = container.offsetWidth;
//设置width的值会致使重排,可是for循环内部
代码执行速度极快,当上面的查询操做致使的重绘
尚未完成,下面的代码又会致使重排,并且这个重
排会强制结束上面的重绘,直接重排,这样对性能影响
很是大。因此咱们通常会在循环外部定义一个变量,这里
面使用变量代替container.offsetWidth;
boxes[i].style.width = newWidth + 'px';
}
复制代码
使用transform
属性去操做动画,这个属性是由合成器单独处理的,因此使用这个属性能够避免布局与绘制。
使用translateZ(0)
开启图层,减小重绘重排。特别在移动端,尽可能使用transform
代替absolute
。建立图层的最佳方式是使用will-change,但某些不支持这个属性的浏览器可使用3D 变形(transform: translateZ(0))来强制建立一个新层。
有兴趣的能够看看这篇文字 前端页面优化
样式的切换最好提早定义好class
,经过class
的切换批量修改样式,避免屡次重绘重排
能够先切换display:none
再修改样式
屡次的append
操做能够先插入到一个新生成的元素中,再一次性插入到页面中。
代码复用,函数柯里化,封装高阶函数,将屡次复用代码封装成普通函数(俗称方法),React
中封装成高阶组件,ES6
中可使用继承,TypeScript
中接口继承,类继承,接口合并,类合并。
在把数据储存在localstorage和sessionstorage
中时,能够再本身定义一个模块,把这些数据在内存中存储一份,这样只要能够直接从内存中读书,速度更快,性能更好。
能不定义全局变量就不定义全局变量,最好使用局部变量代替全局变量,查找的速度要高一倍。
强力推荐阅读:阮一峰ES6教程
以上都是根据本人的知识点总结得出,后期还会有更多性能优化方案等出来,路过点个赞收藏收藏~,欢迎提出问题补充~
下面加入
React
的性能优化方案:
在生命周期函数shouldComponentUpdate
中对this.state
和prev state
进行浅比较,使用for-in
循环遍历二者, 只要获得他们每一项值,只要有一个不同就返回true
,更新组件。
定义组件时不适用React.component , 使用PureComponent代替,这样React
机制会自动在shouldComponentUpdate
中进行浅比较,决定是否更新。
上面两条优化方案只进行浅比较,只对比直接属性的值,固然你还能够在上面加入this.props
和prevprops
的遍历比较,由于shouldComponentUpdate
的生命周期函数自带这两个参数。若是props 和 state
的值比较复杂,那么可使用下面这种方式去进行深比较。
解决:
var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50
复制代码
总结:使用以上方式,能够减小没必要要的重复渲染。
React
的JSX
语法要求必须包裹一层根标签,为了减小没必要要的DOM
层级,咱们使用Fragment
标签代替,这样渲染时候不会渲染多余的DOM
节点,让DIFF
算法更快遍历。
使用Redux
管理全局多个组件复用的状态。
React
构建的是SPA
应用,对SEO
不够友好,能够选择部分SSR
技术进行SEO
优化。
对Ant-design
这类的UI
组件库,进行按需加载配置,从import Button from 'antd' 的引入方式,变成import {Button} from antd
的方式引入。(相似Babel7中的runtime和polifill的区别
).
在React
中一些数据的须要更新,可是却不急着使用,或者说每次更新的这个数据不须要更新组件从新渲染的,能够按期成类的实例上的属性,这样能减小屡次的重复无心义的DIFF
和渲染。
Redux
的使用要看状况使用,若是只是一个局部状态(仅仅是一个组件或者父子组件使用就不要使用Redux
)。对于一个父子、父子孙多层组件须要用到的state数据
,也可使用context上下文
去传递. Context上下文详解,可是复杂项目的多个不一样层次组件使用到的state
,必须上Redux
。
全部的原生监听事件,定时器等,必须在componentWillUnmount
中清除,不然大型项目一定会发生内存泄露,极度影响性能!!!