一文摸透从输入URL到页面渲染的过程

一文摸透从输入URL到页面渲染的过程

从输入URL到页面渲染须要Chrome浏览器的多个进程配合,因此咱们先来谈谈现阶段Chrome浏览器的多进程架构。css

1、Chrome架构

目前Chrome采用的是多进程的架构模式,可分为主要的五类进程,分别是:浏览器(Browser)主进程、 GPU 进程、网络(NetWork)进程、多个渲染进程和多个插件进程;html

  • 浏览器进程。主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
  • 渲染进程。核心任务是将 HTMLCSSJavaScript 转换为用户能够与之交互的网页,排版引擎BlinkJavaScript引擎V8都是运行在该进程中,默认状况下,Chrome会为每一个Tab标签建立一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
  • GPU进程。其实,Chrome刚开始发布的时候是没有GPU进程的。而GPU的使用初衷是为了实现3D CSS的效果,只是随后网页、ChromeUI界面都选择采用GPU来绘制,这使得GPU成为浏览器广泛的需求。最后,Chrome在其多进程架构上也引入了GPU进程。
  • 网络进程。主要负责页面的网络资源加载,以前是做为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
  • 插件进程。主要是负责插件的运行,因插件易崩溃,因此须要经过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面形成影响

了解了Chrome的多进程架构,就可以从宏观上理解从输入URL到页面渲染的过程了,这个过程主要分为导航阶段渲染阶段webpack

2、导航阶段

Ⅰ.浏览器主进程

1.用户输入URL

  • 一、浏览器进程检查url,组装协议,构成完整的url,这时候有两种状况:
    • 输入的是搜索内容:地址栏会使用浏览器默认的搜索引擎,来合成新的带搜索关键字的URL
    • 输入的是请求URL:地址栏会根据规则,给这段内容加上协议,合成为完整的URL
  • 二、浏览器进程经过进程间通讯(IPC)把url请求发送给网络进程;

Ⅱ.网络进程

2.URL请求过程

  • 三、网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,若是有则将该资源返回给浏览器进程;

这里涉及到浏览器与HTTP协议的缓存策略问题,有兴趣的能够看这篇文章:详解HTTP协议web

  • 四、准备IP地址和端口:进行DNS解析时先查找缓存,没有再使用DNS服务器解析,查找顺序为:chrome

    • 浏览器缓存;
    • 本机缓存;
    • hosts文件;
    • 路由器缓存;
    • ISP DNS缓存;
    • DNS递归查询(本地DNS服务器 -> 权限DNS服务器 -> 顶级DNS服务器 -> 13台根DNS服务器)
  • 五、等待TCP队列:浏览器会为每一个域名最多维护6TCP链接,若是发起一个HTTP请求时,这 6TCP链接都处于忙碌状态,那么这个请求就会处于排队状态;解决方案:浏览器

    • 采用域名分片技术:将一个站点的资源放在多个(CDN)域名下面。
    • 升级为HTTP2,就没有6TCP链接的限制了;
  • 六、经过三次握手创建TCP链接:缓存

    123

    • 第一次:客户端先向服务器端发送一个同步数据包,报文的TCP首部中:标志位:同步SYN1,表示这是一个请求创建链接的数据包;序号Seq=xx为所传送数据的第一个字节的序号,随后进入SYN-SENT状态;

    标志位值为1表示该标志位有效。安全

    • 第二次:服务器根据收到数据包的SYN标志位判断为创建链接的请求,随后返回一个确认数据包,其中标志位SYN=1ACK=1,序号seq=y,确认号ack=x + 1表示收到了客户端传输过来的x字节数据,并但愿下次从x+1个字节开始传,并进入SYN-RCVD状态;

    这里要区分标志位ACK和确认号ack服务器

    • 第三次:客户端收到后,再给服务器发送一个确认数据包,标志位ACK=1,序号seq=x+1,确认号ack=y+1,随后进入ESTABLISHED状态;

    服务器端收到后,也进入ESTABLISHED状态,由此成功创建了TCP链接,能够开始数据传送;网络

    • 为何要第三次挥手?避免服务器等待形成资源浪费,具体缘由:

    若是没有最后一个数据包确认(第三次握手),A先发出一个创建链接的请求数据包,因为网络缘由绕远路了。A通过设定的超时时间后还未收到B的确认数据包。

    因而发出第二个创建链接的请求数据包,此次网路通畅,B的确认数据包也很快就到达A。因而AB开始传输数据;

    过了一会A第一次发出的创建链接的请求数据包到达了BB觉得是再次创建链接,因此又发出一个确认数据包。因为A已经收到了一个确认数据包,因此会忽略B发来的第二个确认数据包,可是B发出确认数据包以后就要一直等待A的回复,而A永远也不会回复。

    由此形成服务器资源浪费,这种状况多了B计算机可能就中止响应了。

  • 七、构建并发送HTTP请求信息;

  • 八、服务器端处理请求;

  • 九、客户端处理响应,首先检查服务器响应报文的状态码:

    • 若是是301/302表示服务器已更换域名须要重定向,这时网络进程会从响应头的Location字段里面读取重定向的地址,而后再发起新的HTTP或者HTTPS请求,跳回第4步。
    • 若是是200,就检查Content-Type字段,值为text/html说明是HTML文档,是application/octet-stream说明是文件下载;

  • 十、请求结束,当通用首部字段Conection不是Keep-Alive时,即不为TCP长链接时,经过四次挥手断开TCP链接:

  • 第一次:客户端(主动断开链接)发送数据包给服务器,其中标志位FIN=1,序号位seq=u,并中止发送数据;
  • 第二次:服务器收到数据包后,因为还需传输数据,没法当即关闭链接,先返回一个标志位ACK=1,序号seq=v,确认号ack=u+1的数据包;
  • 第三次:服务器准备好断开链接后,返回一个数据包,其中标志位FIN=1,标志位ACK=1,序号seq=w,确认号ack=u+1
  • 第四次:客户端收到数据包后,返回一个标志位ACK=1,序号seq=u+1,确认号ack=w+1的数据包。

由此经过四次挥手断开TCP链接。

详细过程参见:详解TCP链接的“三次握手”与“四次挥手”(上)

  • 为何要四次挥手?因为服务器不能立刻断开链接,致使FIN释放链接报文与ACK确认接收报文须要分两次传输,即第二次和第三次"挥手";

3.准备渲染进程

  • 十一、准备渲染进程:浏览器进程检查当前url是否与以前打开了渲染进程的页面的根域名相同,若是相同,则复用原来的进程,若是不一样,则开启新的渲染进程;

4.提交文档

  • 十二、提交文档:
    • 渲染进程准备好后,浏览器渲染进程发起“提交文档”的消息,渲染进程接收到消息后与网络进程创建传输数据的“管道
    • 渲染进程接收完数据后,向浏览器发送“确认提交
    • 浏览器进程接收到确认消息后更新浏览器界面状态:安全状态地址栏url前进后退的历史状态更新web页面

3、渲染阶段

在渲染阶段经过渲染流水线在渲染进程的主线程和合成线程配合下,完成页面的渲染;

Ⅲ.渲染进程

渲染进程中的主线程部分

5.构建DOM

  • 1三、先将请求回来的数据解压,随后HTML解析器将其中的HTML字节流经过分词器拆分为一个个Token,而后生成节点Node,最后解析成浏览器识别的DOM树结构。

    能够经过Chrome调试工具的Console选项打开控制台输入document查看DOM树;

渲染引擎还有一个安全检查模块XSSAuditor,是用来检测词法安全的。在分词器解析出来 Token 以后,它会检测这些模块是否安全,好比是否引用了外部脚本是否符合 CSP 规范是否存在跨站点请求等。若是出现不符合规范的内容,XSSAuditor 会对该脚本或者下载任务进行拦截

首次解析HTML渲染进程会开启一个预解析线程,遇到HTML文档中内嵌的JavaScriptCSS外部引用就会同步提早下载这些文件,下载时间以最后下载完的文件为准。

6.构建CSSOM

  • 1四、CSS解析器将CSS转换为浏览器能识别的styleSheets也就是CSSOM:能够经过控制台输入document.styleSheets查看;

    这里要考虑一下阻塞的问题,因为JavaScript有修改CSSHTML的能力,因此,须要先等到 CSS 文件下载完成并生成 CSSOM,而后再执行 JavaScript 脚本,最后再继续构建 DOM。因为这种阻塞,致使了解析白屏

优化方案:

  • 移除jscss的文件下载:经过内联 JavaScript、内联 CSS
  • 尽可能减小文件大小:如经过 webpack 等工具移除没必要要的注释,并压缩 js 文件
  • 将不进行DOM操做或CSS样式修改的 JavaScript 标记上 sync 或者 defer异步引入;
  • 使用媒体查询属性:将大的CSS文件拆分红多个不一样用途的 CSS 文件,只有在特定的场景下才会加载特定的 CSS 文件。

能够经过浏览器调试工具的Network面板中的DOMContentLoaded查看最后生成DOM树所需的时间;

image-20200405110720560

7.样式计算

  • 1五、转换样式表中的属性值,使其标准化。好比将em转换为pxcolor转换为rgb
  • 1六、计算DOM树中每一个节点的具体样式,这里遵循CSS的继承和层叠规则;能够经过Chrome调试工具的Elements选项的Computed查看某一标签的最终样式;

image-20200405110849074

8.布局阶段

  • 1七、建立布局树,遍历DOM树中的全部节点,去掉全部隐藏的节点(好比head,添加了display:none的节点),只在布局树中保留可见的节点。

  • 1八、计算布局树中节点的坐标位置(较复杂,这里不展开);

9.分层

  • 1九、对布局树进行分层,并生成分层树(Layer Tree),能够经过Chrome调试工具的Layer选项查看。分层树中每个节点都直接或间接的属于一个图层(若是一个节点没有对应的层,那么这个节点就从属于父节点的图层)

image-20200405111350260

10.图层绘制

  • 20、为每一个图层生成绘制列表(即绘制指令),并将其提交到合成线程。以上操做都是在渲染进程中的主线程中进行的,提交到合成线程后就不阻塞主线程了;

渲染进程中的合成线程部分

11.切分图块

2一、合成线程将图层切分红大小固定的图块(256x256或者512x512)而后优先绘制靠近视口的图块,这样就能够大大加速页面的显示速度;

Ⅳ.GPU进程

12.栅格化操做

  • 2二、光栅化线程池中将图块转换成位图,一般这个过程都会使用GPU来加速生成,使用GPU生成位图的过程叫快速栅格化,或者GPU栅格化,生成的位图被保存在GPU内存中。

Ⅴ.浏览器主进程

13.合成与显示

  • 2三、合成:一旦全部图块都被光栅化,合成线程就会将它们合成为一张图片,并生成一个绘制图块的命令——“DrawQuad”,而后将该命令提交给浏览器进程。

注意了:合成的过程是在渲染进程的合成线程中完成的,不会影响到渲染进程的主线程执行;

  • 2四、显示:浏览器进程里面有一个叫viz的组件,用来接收合成线程发过来的DrawQuad命令,而后根据DrawQuad命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

到这里,通过这一系列的阶段,编写好的HTMLCSSJavaScript等文件,通过浏览器就会显示出漂亮的页面了。

参考资料:浏览器工做原理与实践

相关文章
相关标签/搜索