这个是个经典的前端/web工程师面试问题。
整体流程
输入 URL-》预处理(本地)-》查询 DNS-》建立连接-》发送请求-》等待响应-》接收数据(网络)-》读取 Cache-》处理渲染(本地渲染)。
优化思路
监控--》优化--》分析 (闭环)
- 白屏时间:</header>结束
- 首屏时间:首屏图片加载结束
- 用户可操作时间:DOMReady / 核心JS加载完毕
- 加载完成:onload / 异步渲染完毕
网络方向:减少请求次数 -减小请求体积 - 加快请求速度 本地: 减少DOM数量量
优化方法
-
预处理 Expire/cache-control
-
查询 DNS 减少DNS查询次数、
-
建立连接 减少HTTP连接、避免跳转、缓存 Ajax、延迟加载 、预加载、使⽤CDN、配置ETags、使⽤Ajax GET、避免空 src 3、发送请求 域名拆分、减少iframe数量、避免404、 减少Cookie大小、静态域名不要带 cookie
-
等待响应 gzip传输、尽早 flush、
-
接收数据(网络)
-
读取 Cache
-
处理渲染(本地渲染) 前端35条优化 减少DOM数量和操作、置顶CSS、⽤<link>代替 @import、避免CSS表达式、避免使用 filters、、 js 置底、压缩JS和CSS、使⽤用事件代理理 。。。
APP
Hybrid -预取、预渲染 -模板本地化 -图片缓存 -长连接、网络探测 - 首屏时间可减少60%+
React Native -用Native View完成渲染 - 体验大幅优化
流程处理
第一步:输入 URL。
涉及概念: URL是统一定位资源符,URL有四种传输协议: 1.http—— 超文本传输协议 2.ftp—— 文件传输协议 3.file—— 主要用于访问本地计算机中的文件 4.https——数据经过加密的超文本传输协议
第二步:查询DNS。
DNS查询是⽐比较耗时的⼀一个操作,为什么?? TTL是 Time To Live的缩写,该字段指定IP包被路由器丢弃之前允许通过的最大网段数量。
nslookup或者dig命令查看域名解析过程
nslookup www.baidu.com
Server: 172.22.~.~ --->返回的是自己的服务器
Address: 172.22.~.~#53 --->返回的是自己的IP
www.baidu.com canonical name = www.a.shifen.com. ----->域名别名记录:别名(CName,Canonical Name)记录
Name: www.a.shifen.com --->目标域名
Address: 220.181.112.244 --->目标返回的Ip
Name: www.a.shifen.com
Address: 220.181.111.188
dig www.baidu.com
; <<>> DiG 9.8.3-P1 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9163
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 5, ADDITIONAL: 5
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 1200 IN CNAME www.a.shifen.com.
www.a.shifen.com. 92 IN A 220.181.112.244
www.a.shifen.com. 92 IN A 220.181.111.188
;; AUTHORITY SECTION:
a.shifen.com. 392 IN NS ns3.a.shifen.com.
a.shifen.com. 392 IN NS ns1.a.shifen.com.
a.shifen.com. 392 IN NS ns5.a.shifen.com.
a.shifen.com. 392 IN NS ns4.a.shifen.com.
a.shifen.com. 392 IN NS ns2.a.shifen.com.
;; ADDITIONAL SECTION:
ns1.a.shifen.com. 346 IN A 61.135.165.224
ns2.a.shifen.com. 346 IN A 180.149.133.241
ns3.a.shifen.com. 346 IN A 61.135.162.215
ns4.a.shifen.com. 346 IN A 115.239.210.176
ns5.a.shifen.com. 347 IN A 119.75.222.17
;; Query time: 7 msec
;; SERVER: 172.22.1.253#53(172.22.1.253)
;; WHEN: Fri Nov 24 14:36:52 2017
;; MSG SIZE rcvd: 260
众所周知,DNS查询过程中的交互是采用UDP的。如果你希望采用TCP方式,需 dig +tcp www.baidu.com
dig非常著名的一个查询选项就是+trace,当使用这个查询选项后,dig会从根域查询一直跟踪直到查询到最终结果,并将整个过程信息输出出来。 dig +trace www.baidu.com
dig +trace www.moa.gov.cn
; <<>> DiG 9.8.3-P1 <<>> +trace www.moa.gov.cn
;; global options: +cmd
. 165815 IN NS f.root-servers.net. ---》'.'代表最高等级DNS服务器称为root
. 165815 IN NS e.root-servers.net.
. 165815 IN NS i.root-servers.net.
. 165815 IN NS d.root-servers.net.
. 165815 IN NS h.root-servers.net.
. 165815 IN NS l.root-servers.net.
. 165815 IN NS g.root-servers.net.
. 165815 IN NS j.root-servers.net.
. 165815 IN NS c.root-servers.net.
. 165815 IN NS k.root-servers.net.
. 165815 IN NS b.root-servers.net.
. 165815 IN NS m.root-servers.net.
. 165815 IN NS a.root-servers.net.
;; Received 492 bytes from 172.22.1.253#53(172.22.1.253) in 55 ms
cn. 172800 IN NS a.dns.cn. --------》递归查询你去找cn.的DNS吧,它的IP是XXX.XXX.XXX.XXX,他负责管这部分的域名。
cn. 172800 IN NS d.dns.cn.
cn. 172800 IN NS e.dns.cn.
cn. 172800 IN NS ns.cernet.net.
cn. 172800 IN NS b.dns.cn.
cn. 172800 IN NS c.dns.cn.
;; Received 295 bytes from 192.5.5.241#53(192.5.5.241) in 28 ms
moa.gov.cn. 86400 IN NS ns.agri.gov.cn.
moa.gov.cn. 86400 IN NS mdns.agri.gov.cn.
;; Received 105 bytes from 202.112.0.44#53(202.112.0.44) in 52 ms
www.moa.gov.cn. 3600 IN CNAME www.f5.moa.gov.cn.
www.f5.moa.gov.cn. 5 IN A 202.127.45.114
;; Received 69 bytes from 202.127.45.1#53(202.127.45.1) in 18 ms
最后返回IP 202.127.45.114 ,
- DNS 优化 DNS存在着多级缓存,从离浏览器的距离排序的话浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
- 浏览器缓存:chrome://dns/
- 系统缓存主要存在/etc/hosts(Linux系统)中:
-
DNS负载均衡 DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡,又叫做DNS重定向。 大家耳熟能详的CDN(Content Delivery Network)就是利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。
-
DNS Prefetching X-DNS-Prefetch-Control 头控制着浏览器的 DNS 预读取功能。 DNS 预读取是一项使浏览器主动去执行域名解析的功能,其范围包括文档的所有链接,无论是图片的,CSS 的,还是 JavaScript 等其他用户能够点击的 URL。 http://www.jianshu.com/p/c3a14a853c79 https://developer.mozilla.org/zh-CN/docs/Controlling_DNS_prefetching
第三步:建立连接
TCP 握手 SYN,SYN ACK, ACK 慢启动和流量控制
- 优化 减少HTTP连接 避免跳转 缓存 Ajax 延迟加载 预加载
第四步:发送请求
- http/https HTTPS在传输数据之前需要客户端与服务器进行一个握手(TLS/SSL握手),在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL使用了非对称加密,对称加密以及hash等。具体过程请参考经典的阮一峰先生的博客TLS/SSL握手过程。 HTTPS相比于HTTP,虽然提供了安全保证,但是势必会带来一些时间上的损耗,如握手和加密等过程,是否使用HTTPS需要根据具体情况在安全和性能方面做出权衡。
- http 请求 发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口(HTTP协议80/8080, HTTPS协议443)。HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文。 常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
第五步:等待响应
http状态码是由3位数组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息–表示请求已接收,继续处理。 2xx:成功–表示请求已被成功接收、理解、接受。 3xx:重定向–要完成请求必须进行更进一步的操作。 4xx:客户端错误–请求有语法错误或请求无法实现。 5xx:服务器端错误–服务器未能实现合法的请求。 平时遇到比较常见的状态码有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500(分别表示什么请自行查找)。
第六步:
第七步:处理渲染
现代浏览器渲染页面
的过程是这样的:解析HTML以构建DOM树 –> 构建渲染树 –> 布局渲染树 –> 绘制渲染树。 步骤详细解释: 第一步:渲染引擎开始解析html,根据标签构建DOM树, DOM树是由HTML文件中的标签排列组成。 第二步:根据css样式构建渲染树,包括元素的大小、颜色,隐藏的元素不会被构建到该树中。渲染树是在DOM树中加入CSS或HTML中的style样式而形成。渲染树只包含需要显示在页面中的DOM元素,像<head>元素或display属性值为none的元素都不在渲染树中。 第三步:根据css样式构建布局树,主要是确定元素要显示的位置。 第四步:根据前面的信息,绘制渲染树。
在浏览器还没接收到完整的HTML文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送HTTP请求重复上述的步骤。在收到CSS文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。
涉及到两个概念: reflow(回流)和repain(重绘)。DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。
不同的浏览器有不同的渲染引擎,对于渲染引擎的使用总结如下: Trident(MSHTML)内核:IE,MaxThon,TT,The World,360,搜狗浏览器等 Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等 Presto内核:Opera7及以上 Webkit内核:Safari,Chrome等
为什么要前端优化时,建议把 JS 文件放在最后??
JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。
当文档加载过程中遇到JS文件,HTML文档会挂起渲染过程,不仅要等到文档中JS文件加载完毕还要等待解析执行完毕,才会继续HTML的渲染过程。原因是因为JS有可能修改DOM结构,这就意味着JS执行完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS文件的加载不影响JS文件的加载,但是却影响JS文件的执行。JS代码执行前浏览器必须保证CSS文件已经下载并加载完毕。
https://segmentfault.com/a/1190000006879700
减少 dom事件原因
利用 js 事件冒泡原理:在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。