【浏览器】输入URL到显示页面发生了什么?

195 阅读6分钟

前置知识点

DNS:Domain Name System 域名系统(基于RFC规范解释)
DNS是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。
DNS 用的网络协议⭐⭐⭐:

  • DNS 在区域传输的时候用的 tcp
    • 将一个区域文件传输到多个 DNS服务器的过程叫做区域传输
  • 域名解析的时候用的是 udp

(一)从浏览器输入url后都经历了什么⭐⭐⭐⭐⭐

  1. 浏览器的地址栏输入URL并按下回车
  2. 查看浏览器缓存,比较缓存是否过期
    • 如果访问过该url,浏览器查找当前URL是否存在缓存(浏览器缓存是在本地保存资源副本),然后在缓存中查询是否有要请求的文件。
    • 如果缓存查找成功,它会拦截请求,返回该资源的副本,并直接结束请求,而不会再去源服务器重新下载。
    • 如果缓存查找失败,就会进入网络请求过程了
  3. DNS域名解析,拿到对应的IP和端口号
    • 如果没有访问过该url,DNS就解析URL对应的IP,并获取端口号
  4. 根据IP建立TCP连接(知识点:三次握手)
  5. HTTP发起请求
    • 握手成功,连接到了Web服务器,浏览器会根据解析到的IP地址和端口号发起HTTP请求。
  6. 服务器处理请求,浏览器接收HTTP响应
  7. 关闭TCP连接(知识点:四次挥手)
  8. 渲染页面,构建DOM树。(知识点:浏览器渲染的主要流程)

(二)浏览器渲染的主要流程是什么?⭐⭐⭐⭐⭐

c8a51ab77f6743efb929ae9730c12933.png

  • 根据HTML代码深度优先遍历生成DOM树(DOM Tree
    • DOM树由dom元素及属性节点组成,树的根是document对象
  • 根据 CSS 代码 生成CSS规则树CSSOM (CSS Rule Tree
    浏览器的CSS解析器解析css文件时,对CSS规则是从右到左匹配查找,如果选择器嵌套层数太多会造成CSS Tree加载变慢
  • 将 DOM Tree 和 CSSOM 整合形成渲染树(Render Tree
  • 根据Render Tree 渲染页面(知识点:回流重绘
    • 遇到 <script>(即js代码)则暂停渲染,优先加载并执行JS代码,完成再继续
  • 直至把Render Tree渲染完成
graph TD
HTML --> DOMTree
CSS --> CSSOM
DOMTree --> RenderTree
CSSOM --> RenderTree
RenderTree--> 渲染页面/回流重绘

  • DOM树、CSSOM树和渲染树三者的构建并无先后条件和先后顺序,并非完全独立而是会有交叉并行构建的情况。因此会形成一边加载,一边解析,一边渲染的工作现象。
  • 其中遇到CSS加载的时候,CSS不会阻塞DOM树的解析,但是会阻塞DOM树的渲染,并且CSS会阻塞下面的JS的执行
  • 然后是JS加载,JS加载会影响DOM的解析,之所以会影响,是因为JS可能会删除添加节点,如果先解析后加载的话,DOM树还得重新解析,性能比较差。
  • 如果不想阻塞DOM树的解析的话,可以给script添加一个defer或者async的标签。

说一说defer 和 async⭐⭐⭐⭐⭐

(1)首先在正常情况下,script 标签是会阻塞 DOM 的解析的,所以我们要尽量不要把script 放到 head 里,要尽量放到 body 的最下方。这样不至于会有白屏的效果;
(2)然后是 defer和 async;他们两个是异步加载 js 代码的,都不会阻塞DOM解析

  • defer(推迟):等dom 渲染完之后才运行该 js 代码
    • 给 script 标签添加 defer 属性,就不会阻塞 dom 的解析了,等 dom 渲染完之后才运行该 js 代码
    • 如果是多个 script 标签都添加了 defer 属性的话,那么它们是按照顺序执行的(第一个全部执行完毕之后才能执行第二个)
    • defer 的 script 是在 DOMContentLoaded 之前运行的。
      • window.onload和DOMContentLoaded区别?
        ① window.onload 资源全部加载完才能执行,包括图片
        ② DOMContentLoaded DOM渲染完成即可,图片可能尚未下载
  • async:等下载完成之后会立即运行js 代码
    • 给 script 添加 async 属性之后,会异步下载 js 代码,等下载完成之后会立即运行js 代码
    • 多个 script 标签同时设置了 async 是没有先后顺序的,谁先加载完谁就先运行。
    • 如果 script 标签没有操作任何 dom 信息,且不彼此依赖的话,可以使用 async

(三)重排与重绘 ⭐⭐⭐⭐⭐

1. 说一下重排与重绘

(1)重排 :表现为重新生成布局,重新排列元素

DOM的变化影响了元素的几何信息,浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。

  • 页面至少会进行一次回流,页面第一次加载的时候。
  • 当我们操作 DOM 时,使其结构发生改变,从而影响了整体布局,这个过程就会发生回流。
    具体如下:
    • 当元素的 width、height、margin、padding、left、top 发生改变的时候会发生回流
    • 使 DOM节点增减或移动
    • 读写 offset、client、scroll 时,浏览器为了获取这些值,会进行回流操作
    • 使用 window.getComputedStyle的时候

(2)重绘 :表现为某些元素的外观被改变

当改变元素时,只是改变了它的外观,比如背景颜色等,而没有影响到它的布局,这个时候会发生重绘

  • 回流必将引起重绘;重绘不一定会引起回流

2. 如何触发重排和重绘?

任何改变用来构建渲染树的信息都会导致一次重排或重绘:

  • 添加、删除、更新DOM节点
  • 通过display: none隐藏一个DOM节点:触发重排和重绘
  • 通过visibility: hidden隐藏一个DOM节点:只触发重绘,因为没有几何变化
  • 移动或者给页面中的DOM节点添加动画
  • 添加一个样式表,调整样式属性
  • 用户行为,例如调整窗口大小,改变字号,或者滚动。

3. 如何避免或减少重排和重绘?

  • 尽量避免频繁使用style,而是使用修改class的方式
  • 使用 creeateDocumentFragment
  • 对于 resize 和 scroll 进行防抖节流处理
  • 集中改变样式,不要一条一条地修改 DOM 的样式。
  • 不要把 DOM 结点的属性值放在循环里当成循环里的变量。
  • 为动画的 HTML 元件使用 fixedabsoultposition,那么修改他们的 CSS 是不会 reflow 的。
  • 不使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。
  • 尽量只修改position:absolutefixed元素,对其他元素影响不大
  • 动画开始GPU加速,translate使用3D变化
  • 提升为合成层
  • 将元素提升为合成层有以下优点:
    • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
    • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
    • 对于 transform 和 opacity 效果,不会触发 layout 和 paint 提升合成层的最好方式是使用 CSS 的 will-change 属性: