天天看点

从输入内容到展示页面全过程详解整体流程其他

整体流程

将整个流程分为导航流程和渲染流程两部分。

导航流程

  1. 处理用户输入
    • 判断是搜索内容还是url
    • 搜索内容则直接用默认搜索引擎,合成带搜索关键字的URL
    • url,则判断url规则,根据规则,把内容加上协议,合成完整的URL
  2. 监听

    beforeunload

    事件,

    beforeunload

    事件允许页面在退出之前执行一些数据清理操作,还可以询问用户是否要离开当前页面
    • 用户可以通过

      beforeunload

      事件来取消导航,让浏览器不再执行任何后续工作
  3. 进入页面资源请求过程。浏览器进程会通过进程间通信把 URL 请求发送至网络进程,网络进程接收到 URL 请求后,会在这里发起真正的 URL 请求流程
    • 查找本地缓存,如果本地缓存中没有,则进入网络请求流程,否则直接将缓存资源返回给浏览器进程
    • DNS 解析域名,得到实际IP地址
    • 如果是HTTPS协议,还需要建立TLS/SSL连接
    • 利用IP地址与服务器建立TCP连接
    • 连接建立后,浏览器端构造请求行、请求头等信息,并把和该域名相关的 Cookie 等数据附加到请求头中,然后向服务器发送构建的请求信息
    • 服务器接收到请求信息后,会根据请求信息生成响应数据(包括响应行、响应头和响应体等信息),并发给网络进程。等网络进程接收了响应行和响应头之后,就开始解析响应头的内容了
  4. 在接收到服务器返回的响应头后,网络进程开始解析响应头,如果发现返回的状态码是

    301

    或者

    302

    ,那么说明服务器需要浏览器重定向到其他 URL。这时网络进程会从响应头的 Location 字段里面读取重定向的地址,然后再发起新的 HTTP 或者 HTTPS 请求,一切又重头开始了。如果状态码是

    200

    ,则继续处理请求。
  5. 浏览器会根据

    Content-Type

    的值来决定如何显示响应体的内容。如果

    Content-Type

    字段的值被浏览器判断为下载类型,那么该请求会被提交给浏览器的下载管理器,同时该 URL 请求的导航流程就此结束。但如果是 HTML,那么浏览器则会继续进行导航流程。
  6. 准备渲染进程:默认情况下,Chrome 会为每个页面分配一个渲染进程,也就是说,每打开一个新页面就会配套创建一个新的渲染进程。但是,也有一些例外,在某些情况下,浏览器会让多个页面直接运行在同一个渲染进程中。
    • Chrome 的默认策略是

      process-per-site-instance

      ,即每个标签对应一个渲染进程。但如果从一个页面打开了另一个新页面,而新页面和当前页面属于同一站点(same-site,根域名和协议相同)的话,那么新页面会复用父页面的渲染进程。
  7. 提交文档:浏览器进程将网络进程接收到的 HTML 数据提交给渲染进程
    • 首先当浏览器进程接收到网络进程的响应头数据之后,便向渲染进程发起“提交文档”的消息;
    • 渲染进程接收到“提交文档”的消息后,会和网络进程建立传输数据的“管道”;
    • 等文档数据传输完成之后,渲染进程会返回“确认提交”的消息给浏览器进程;
    • 浏览器进程在收到“确认提交”的消息后,会更新浏览器界面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 Web 页面。这也就解释了为什么在浏览器的地址栏里面输入了一个地址后,之前的页面没有立马消失,而是要加载一会儿才会更新页面。

至此,导航流程结束。浏览器的导航过程涵盖了从用户发起请求到提交文档给渲染进程的中间所有阶段。

  1. 渲染阶段:一旦文档被提交,渲染进程便开始页面解析和子资源加载了
    • 一旦页面生成完成,渲染进程会发送一个消息给浏览器进程,浏览器接收到消息后,会停止标签图标上的加载动画

渲染流程

渲染流水线:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。

  • 开始每个子阶段都有其输入的内容;
  • 然后每个子阶段有其处理过程;
  • 最终每个子阶段会生成输出内容。
  1. 构建DOM树
    • 因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构 —— DOM 树
  2. 样式计算
    • 把 CSS 转换为浏览器能够理解的结构

      styleSheets

      ,可以在控制台输入

      document.styleSheets

      查看。该结构同时具备了查询和修改功能。
    • 转换样式表中的属性值,使其标准化。将所有值转换为渲染引擎容易理解的、标准化的

      计算值

      。如 red 被解析成 rgb(255,0,0),bold 被解析成 700。
    • 根据

      继承规则

      层叠规则

      计算出 DOM 树中每个节点的具体样式。
      • 关于继承,要注意

        UserAgent

        样式,它是浏览器提供的一组默认样式,如果你不提供任何样式,默认使用的就是

        UserAgent

        样式。
      • 层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称“层叠样式表”正是强调了这一点。
    这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。
  3. 布局阶段:计算出DOM树中可见元素的几何位置。
    • 创建布局树:只包含可见元素。遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中。
    • 布局计算:计算布局节点的坐标位置。
  4. 分层:因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-index 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。

    通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。

    渲染引擎为特定的节点创建新的图层的条件:

    1. 拥有层叠上下文属性的元素被提升为单独一层。明确定位属性(

      z-index

      position

      )的元素、定义透明属性(

      opacity

      )的元素、使用 CSS 滤镜(

      filter

      )的元素等,都拥有层叠上下文属性。
    2. 需要剪裁(

      clip

      )的地方也会被创建为图层。如在规定了

      width

      div

      块内写入很多文字,出现这种裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。
  5. 图层绘制:在图层绘制阶段,输出的内容就是这些待绘制列表。绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的

    合成线程

    来完成的。当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程。合成线程会按照视口(可见区域)附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。图块是栅格化执行的最小单位。
  6. 栅格化:渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。

    通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。GPU 操作运行在 GPU 进程中,如果栅格化用到了 GPU,那么最终生成位图的操作是在 GPU 中完成的,涉及了跨进程操作。

  7. 合成和显示:一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
    从输入内容到展示页面全过程详解整体流程其他

其他

DNS解析

解析过程:

  1. 浏览器自身缓存查找,域名被缓存的时间也可通过TTL属性来设置
  2. 操作系统缓存查找(C盘hosts 只读)
  3. 请求本地域名服务器Local DNS Server(80%找到)
  4. 请求Root DNS,返回gTLD Server(国际顶尖域名服务器)给LDNS,LDNS请求gTLD,gTLD查找并返回域名对应的Name Server地址(网站注册的域名服务器)
  5. Name Server根据映射关系表找到目标ip,返回给LDNS
  6. LDNS缓存这个域名和对应的ip
  7. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束
. -> .com -> google.com. -> www.google.com.
           

DNS优化

DNS缓存

DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种:

  • 浏览器缓存
  • 系统缓存
  • 路由器缓存
  • IPS服务器缓存
  • 根域名服务器缓存
  • 顶级域名服务器缓存
  • 主域名服务器缓存

DNS负载均衡(DNS重定向)

CDN就是利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。

DNS预解析(dns-prefetch)

提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提高网站的访问速度

  1. html 源码下载完成后,会解析页面的包含链接的标签,提前查询对应的域名

    DNS Prefetch应该尽量的放在网页的前面,推荐放在

    <meta charset=""/>

    后面。

    在HTTPS页面开启隐式的DNS Prefetch:

  2. 对于访问过的页面,浏览器会记录一份域名列表,当再次打开时,会在 html 下载的同时去解析 DNS

浏览器底层缓存进行了建模,当Chrome浏览器启动的时候,就会自动的快速解析浏览器最近一次启动时记录的前10个域名。所以经常访问的网址就没有DNS解析的延迟,打开速度更快

HTTPS加密通信

从输入内容到展示页面全过程详解整体流程其他

(下一篇详细介绍)

TCP三次握手 四次挥手

tcp 将 http 长报文划分为短报文,通过三次握手与服务端建立连接,进行可靠传输。

三次握手

为什么是三次?

信道不可靠,但数据传输要可靠。三次握手不是 TCP 本身的要求,而是为了满足“在不可靠信道上可靠地传输信息”这一需求所导致的。

四次挥手

tcp/ip的并发限制

浏览器对同一域名下并发的tcp连接是有限制的(2-10个不等)。

而且在http1.0中往往一个资源下载就需要对应一个tcp/ip请求。

所以针对这个瓶颈,又出现了很多的资源优化方案。

get 和 post 的区别

get 和 post 虽然本质都是 tcp/ip,但两者除了在 http 层面外,在 tcp/ip 层面也有区别。

get 会产生一个tcp数据包,post 两个。

具体就是:

  • get请求时,浏览器会把 headers和 data一起发送出去,服务器响应200(返回数据),
  • post请求时,浏览器先发送 headers,服务器响应 100continue,浏览器再发送 data,服务器响应200(返回数据)。

再说一点,这里的区别是 specification(规范)层面,而不是 implementation(对规范的实现)。

JS 阻塞

js 引擎线程与浏览器渲染线程互斥。当执行 js 代码时会阻塞 HTML 的渲染。

因此常用以下方法处理 js:

  1. 将 js 放在 body 的最后
  2. 给 js 加上 defer / async
  3. 将代码放在 onload 函数中

具体可以参考以下两篇文章:

js的defer属性、async属性和onload

将script放在body中内容的最后的原因详解