从输入url到页面渲染

509 阅读6分钟

一、浏览器的架构

介绍

单进程架构下,由于线程崩溃导致浏览器整个崩溃的问题无法解决,因此现在一般采用chormium的多进程架构

  • 一个浏览器进程,流程控制,进行进程间的通信
  • 一个网络进程,进行网络请求的提交
  • 一个GPU进程,开启硬件加速
  • 多个渲染进程,一般为每个页面开启一个渲染进程
  • 多个插件进程,当使用插件时开启

问题

(1) 打开一个页面一般几个进程

打开一个页面一般四个进程,浏览器进程、网络进程、GPU进程和一个渲染进程,特殊情况下还会开启插件进程

(2) 为什么一个页面崩掉,其他页面一般无影响

页面崩掉的是由于当前页面对应的渲染进程崩溃掉,但是由于浏览器多个渲染进程之间一般是没有联系的,所以只要浏览器进程存在,其他页面不受影响,增加了浏览器的稳定性

(3) 为什么有的时候一个页面崩掉会影响其他页面

通常情况下是一个页面使用一个进程,但是,有一种情况,叫"同一站点(same-site)",具体地讲,我们将“同一站点”定义为根域名(例如,xxx.com)加上协议(例如,https:// 或者http://),还包含了该根域名下的所有子域名和不同的端口,如以下:

aaa.xxx.com

www.xxx.com

www.xxx.com:3000

这种情况下,如果从当前页面打开另外的页面,如果这两个页面属于同一站点的话,浏览器会将渲染进程复用,即两个页面共同使用同一个渲染进程,所以一个页面崩溃会导致使用同一个渲染进程的页面都崩溃掉

二、 建立连接获取资源

过程

  1. 浏览器进程根据用户输入,向网络进程提交请求

  2. 网络进程首先查看是否有对应可用缓存

    1. 如果有,则进行网络请求的拦截,将资源返回并设置状态码为304
    2. 如果没有,则进行网络请求
      1. 首先进行DNS域名解析,获得对应的ip地址
      2. 根据ip地址,建立tcp连接
      3. 发送http请求,由于http/1.1 是支持长连接的,所以我们可以发起多个http请求
      4. 如果存在重定向,则需要重新执行2.1-2.3的过程
  3. 处理请求的资源,进行页面的渲染

问题

(1) 不同层的作用

  1. http层 生成针对目标web服务器的http请求报文
  2. tcp层,建立连接,将请求分割为报文段,通过慢启动+拥塞避免、快重传+快恢复进行可靠传输
  3. ip层,根据目标ip地址,进行数据包的中转和传送

(2) 为什么要采用进程间通信的方式,将网络请求和渲染部分分离开?

网络资源通过网络进程下载下来,然后通过IPC提交给渲染进程。整个过程我们认为网络资源是不安全的,如果我们 将权限全部交给渲染进程,一旦恶意资源被执行,就可能通过这个方式控制操作系统,所以我们需要在操作系统和渲染进程之间建立一道墙进行保护——安全沙箱。

安全沙箱最小的保护单位是进程,并且能限制进程对操作系统资源的访问和修改,这就意味着如果要让安全沙箱应用在某个进程上,那么这个进程必须没有读写操作系统的功能,比如读写本地文件、发起网络请求、调用 GPU 接口等。

所以对应的我们只让渲染进程进行对文档的解析和渲染,但是文件、请求、存储等交给浏览器内核,这样就建立了安全沙箱,使得渲染进程使用操作系统功能,只能通过IPC通信才能完成,增加了浏览器的安全性

(3) 为什么图片要通过浏览器内核进行展示,而不是通过渲染进程进行展示 ,渲染进程只进行生成图片

渲染进程需要渲染出位图,将图片通过IPC交由浏览器内核进行渲染展示。操作系统将输入事件传递给浏览器内核,经由浏览器内核对输入事件进行分发,限制了渲染进程监听用户输入功能的能力。

三、渲染页面

整体过程

  1. 渲染进程对HTML进行解析,生成DOM树
  2. 渲染进程将CSS样式表生成对应的CSSOM树,计算出对应的DOM节点的style
  3. 创建布局树,计算元素信息
  4. 对布局树,进行分层绘制
  5. 将图层分成块,进行光栅化转成位图 【通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。】
  6. 合成线程发送绘制图块命令 DrawQuad 给浏览器进程 【这一步由第二部分可知,我们需要进行IPC】
  7. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上

问题

(1) 为什么把js放在html文档下边

由于渲染进程中存在GUI渲染线程和js引擎线程,GUI负责界面的绘制,js负责交互逻辑,所以当解析html文档时,如果遇到js代码,会切换线程,此时html的解析会停止,直到js加载完成,如果js非常大,会造成页面卡顿假死的情况,极大的影响用户体验。

所以一般将js放在body后。当然也存在js不阻塞的解析的情况,即在js标签上增加defer字段,标识可以与dom渲染并行处理,或者增加async 进行异步处理(下载完成立刻执行)

(2) css为什么要放在head标签中

因为将CSS放在head中,可以提前构建CSSOM树,确定每个DOM节点的style信息,这样当解析到某个DOM节点时,即可知道他的style,解析完DOM节点后即可 Render Tree。【一次render】

如果将CSS放在body尾部,解析完DOM后,网页即会Render Tree,还需要再解析CSSOM,然后再对DOM进行style的更新,再进行一次Render Tree,即产生了reflow,产生性能问题。【两次render 造成reflow】