|
从用户输入URL到页面显示这中间浏览器做了什么,这应该算是一道非常经典的面试题了。不仅仅能考察面试者对于浏览器渲染原理的基本了解,还能从中延伸出很多的知识点和性能优化点。那今天我们就通过三张流程图,来重新捋清楚这题的思路吧。第一张图--从输入URL到页面展示完整流程示意图整体流程图第一张图当然就是整体的流程图。图中也可以看出,这个问题的回答离不开浏览器进程相关的知识。所以,我们先来快速学习一下浏览器架构的简单知识。目前的Chrome浏览器为多进程架构,包括1个浏览器主进程、1个GPU进程、1个网络进程、多个渲染进程和插件进程。浏览器进程主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。渲染进程将HTML、CSS和JavaScript转换为用户可以与之交互的网页,排版引擎Blink和JavaScript引擎V8都运行在该进程中。GPU进程用来实现3DCSS效果,绘制网页、Chrome的UI界面。网络进程负责页面的网络资源加载。插件进程负责插件的运行。有了浏览器架构的知识,再结合整体流程图,可以大致将流程描述如下。浏览器进程接收到用户输入的URL后,将URL转发给网络进程接着在网络进程中发起URL请求网络进程接收并读取响应头信息后将数据转发给浏览器进程浏览器进程接收到响应头数据后,发送提交导航信息到渲染进程渲染进程接到消息后,和网络进程建立数据管道,准备开始接收HTML数据接着渲染进程向浏览器进程发送确认文档提交的消息浏览器进程接收到消息后,会移除旧文档,更新页面状态而渲染进程也开始了页面解析和子资源加载,这些数据经过中间模块的处理,最终形成页面这第一张图一开始看可能会有点迷茫,可以先大致瞅一眼过程,阅读完全文后再回头看也许会清晰很多。第二张图--URL请求流程图URL请求流程图从输入URL到页面显示这个过程发生了什么,具体可以分成导航流程和渲染流程两部分来回答,每个部分也有若干子流程。用户发出URL请求到页面开始解析的这个过程,叫做导航。导航流程中最重要的部分就是URL请求流程。不过还是先来了解一下导航流程都有哪些具体步骤。用户输入首先,用户在地址栏输入关键字,地址栏会判断关键字是搜索内容还是请求的URL,前者的话地址栏会使用浏览器默认的搜索引擎合成新的带关键字的URL,后者则根据规则加上协议合成完整的URL。键入回车后,当前页面执行beforeunload事件。从图中可以看出,浏览器进入加载状态后,页面还是之前打开的内容,这时需要等待提交文档阶段,页面内容才会被替换。URL请求过程接下来,浏览器进程会通过进程间通信(IPC)把URL请求发送至网络进程,网络进程接收到URL请求后,会经历下图的阶段。URL请求流程图在这里先呼应开头流程图中提到的重定向,如果服务端返回的响应头中状态码是301或者302,那么网络进程会从响应头的Location字段里面读取重定向的地址,然后再发起新的HTTP或者HTTPS请求,否则浏览器继续处理该请求。接着,浏览器会根据返回响应头中的content-type值判断响应体数据的类型,text/html说明是HTML格式,浏览器会继续进行导航流程,而application/octet-stream则是字节流类型,浏览器会按照下载类型来处理请求。由于Chrome的页面渲染是运行在渲染进程中的,所以接下来就需要准备渲染进程了。准备渲染进程Chrome的默认策略是,每个标签对应一个渲染进程。但如果从一个页面打开了另一个新页面,而新页面和当前页面属于同一站点(根域名加上协议,还包含了该根域名下的所有子域名和不同的端口)的话,那么新页面会复用父页面的渲染进程。如下图所示。渲染进程准备好之后,还不能立即进入文档解析状态,因为此时的文档数据还在网络进程中,并没有提交给渲染进程,所以下一步就进入了提交文档阶段。提交文档这是指浏览器进程将网络进程接收到的HTML数据提交给渲染进程,具体流程如下:浏览器进程收到网络进程的响应头数据后,向渲染进程发起提交文档的消息渲染进程收到后,会和网络进程建立传输数据的管道数据传输完后,渲染进程会返回确认提交的信息给浏览器进程浏览器进程在收到消息后,会更新浏览器界面状态,包括安全状态、地址栏的URL、前进后退的历史状态,并更新Web页面更新后的浏览器状态栏如下图所示。在这个环节中,深挖点和性能优化点应该都在URL请求阶段。比如,TCP协议是如何把数据包送达应用程序的,和UDP协议有什么不同?首先由于TCP的特性,数据需要拆分成一个个数据包来回多次进行传输的,通常1个HTTP的数据包在14KB左右。下图就是简化的TCP网络四层传输模型。上层将含有“转转”的数据包交给传输层传输层会在数据包前面附加上TCP头,组成新的TCP数据包,再将新的TCP数据包交给网络层网络层再将IP头附加到数据包上,组成新的IP数据包,并交给底层数据包被传输到主机B的网络层,在这里主机B拆开IP头信息,并将拆开来的数据部分交给传输层在传输层,数据包中的TCP头会被拆开,并根据TCP中所提供的端口号,把数据部分交给上层的应用程序最终,含有“转转”信息的数据包就旅行到了主机B上层应用程序这里TCP协议提供重传机制和数据包排序机制,保证了数据传输的可靠性。而对比之下,UDP协议通过端口号就能把指定的数据包发送给指定的程序。流程和上图TCP协议大体一致,不过UDP协议只能校验数据的正确性,以及拥有很快的传输速度,但是不能保证数据的和可靠性和完整性。通常会应用在一些关注速度、但不那么严格要求数据完整性的领域,如在线视频、互动游戏等。至于TCP三次握手和四次挥手的机制,感觉又可以写一篇文章了,看官们可以右转Google一下。资源加载阶段的性能优化,关注点应该在减少需要加载关键资源的个数和关键资源的大小。而下一篇文章我们会介绍HTTP的优化手段,大家可以关注一下。第三张图--渲染流程图好咯下面是最后一part。文档被提交后,导航流程就结束了,渲染进程便开始页面解析和子资源加载。如上图所示,输入的是HTML、CSS、JavaScript数据,这些数据经过中间渲染模块的处理,最终输出为屏幕上的像素,这样的处理流程叫做渲染流水线。按照渲染的时间顺序,渲染流水线可以分成下面几个阶段:构建DOM树、样式计算、布局阶段、分层、绘制、光栅化和合成。接下来,我们就来详解图中的各个子阶段。构建DOM树由于浏览器无法直接理解和使用HTML,所以需要由HTML解析器将HTML转换为浏览器能够理解的结构--DOM树。在浏览器中打印document,可以看到一个完整的DOM结构,DOM结构和HTML的内容几乎是一样的,不过DOM是保存在内存中的树结构,可以通过JavaScript来查找和修改其内容。样式计算有了DOM节点之后,需要有让节点拥有正确的样式。而同样,浏览器也无法理解纯文本的CSS,所以当渲染引擎收到CSS文本时,会执行转换成styleSheets的操作。在控制台打印document.styleSheets能看到样式结构的数据,该结构同时具备了查询和修改功能,这会为后面的样式操作提供基础。然后,将样式表中的属性值转换成渲染引擎容易理解的、标准化的计算值。如2em、blue、bold,需要转成32px、rgb(0,0,255)、700。最后是根据CSS的层叠规则和继承队则,计算DOM树中每个节点的具体样式。布局阶段使用DOM树和DOM树中的样式,构建只包含可见元素的布局树,并计算布局树节点的坐标位置。分层为了方便地实现页面中一些复杂的3D变换、页面滚动,或者使用z-indexing做z轴排序,渲染引擎为特定的节点生成专用的图层,没有特定图层的节点就从属于父节点的图层,这些图层生成对应的图层树,并叠加构成了最终的页面图像。绘制图层中元素的前景、背景、边框都需要单独的指令去绘制,这些指令被按顺序组成一个待绘制列表。光栅化主线程把绘制列表交给合成线程,合成线程将图层划分为块,优先将视口附近的图块生成位图,位图被保存在GPU的内存中。合成一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令提交给浏览器进程。浏览器进程里面有一个叫viz的组件,用来接收合成线程发过来的DrawQuad命令,然后根据DrawQuad命令,将页面内容绘制到内存中,最后再将内存显示在屏幕上。到这里,HTML、CSS、JavaScript等文件,经过浏览器就会显示出页面了。在DOM解析过程中,如果遇到script、link、style等标签都有可能会阻塞这个过程。因为JS可能要修改当前生成的DOM结构,也有可能修改CSSOM。简而言之。持续DOM的构建,依赖于JS的执行,JS的执行依赖于CSSOM的构建。这一部分自然也影响了首屏时间,所以Chrome浏览器提供了一些优化操作。当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析下载HTML文件中包含的JavaScript、CSS等文件。而我们也可以使用CDN来加速文件的下载,没有DOM相关操作的JS文件,可以通过async或defer标记来设置为异步加载。还可以使用webpack的webpackChunkName注释,将首屏组件和非首屏组件分开打包,缩短白屏展示时长。此外,还有三个经常碰到然后又和渲染流程有关的概念,重排、重绘和合成。通过JavaScript或者CSS修改了元素的几何属性比如宽度高度等,浏览器会触发布局以及之后的子阶段,这就是重排。结合渲染流程图也可以看出,重排需要更新完整的渲染流水线,所以开销很大。如果只修改了元素的绘制属性如背景颜色等,会省去布局和分层阶段,直接进入Paint阶段,这就是重绘,执行效率会比重排要高。而合成的概念,则解释了为什么CSS动画比JS的动画要高效。例如如果使用transform来实现动画效果,渲染引擎会跳过布局和绘制两个阶段,在非主线程合成,这样便能提高绘制效率。讲了不少啦,写着写着觉得给自己挖了好多个坑,每一个知识点感觉都可以延伸出一篇文章的样子。所以当被问到这个经典的面试题时,你知道要怎么准备和回答了么?参考资料李兵--极客时间《浏览器工作实践与原理》HowBrowsersWorkhttps://www.html5rocks.com/en/tutorials/internals/howbrowserswork/HTTP教程https://developer.mozilla.org/zh-CN/docs/Web/HTTPInsidelookatmodernwebbrowserhttps://developers.google.com/web/updates/2018/09/inside-browser-part2#a_simple_navigation
|
|