浏览器渲染页面的主体流程

1,228 阅读5分钟

当我们在浏览器输入网址后;浏览器都会做哪些事情才会让我们看见页面呢?

  • 首先在客户端浏览器输入网址:www.baidu.com
  • 客户端浏览器向服务器发送请求 HTTP REQUEST(省略很多细节步骤)
  • 服务器端存储着百度官网项目的原代码
  • 服务器收到请求后:服务器端把指定文中的代码返回给客户端 HTTP RESPONSE

一、进程/线程

一个进程中,会包含零到多个线程

1、进程 process

  • 电脑端安装很多的应用软件,每当运行一个应用程序,都相当于开辟了一个进程
  • 而对于浏览器来说,每新建一个页卡访问一个页面,都是新开辟一个进程

2、线程 thread

  • 每一个进程当中可能还会同时做多件事情,如果同时做多件事情,则会开辟多个线程

二、浏览器常用线程

浏览器是“多线程”的,但是JS渲染或者页面渲染是“单线程”的

  • GUI 渲染线程
    • 渲染和绘制页面
  • JS 引擎线程
    • 运行和渲染JS代码
  • 事件管控和触发线程
  • 定时器管控和触发线程
  • 异步 HTTP 请求线程
  • ......

三、同步/异步

1、同步编程

  • 单线程
  • 一次只能处理一件事情,当前这件事情处理完,才能继续处理下一件事情

2、异步编程

  • 同时可以进行好几件事情(一般是基于多线程并发完成的)
  • JS 中的异步编程,有自己一些特殊的处理方式
    • 队列 Queue
    • 事件循环 EventLoop

例题:

let n = 10;
setTimeout(() => {
    n++;
    console.log(n);
}, 0);
console.log(n);
for (let i = 0; i < 99999999; i++) {}
console.log(n);

按步解析:

  • 1、JS 是单线程的,所以在 “栈” 中,代码一定是按照顺序,自上而下依次执行的

  • 2、代码执行过程中如果遇到一个异步的操作代码:

    • 定时器(设置定时器的操作是同步的(立即设置),异步指的是间隔多久后执行指定的函数)
    • 事件绑定(监听)
    • AJAX的异步请求
    • PROMISE/ASYNC/AWAIT
    • ......
  • 事件对列 EventQueue

    • 3、当遇到定时器之后:浏览器默认开辟一个 事件队列 EventQueue
    • 4、JS 代码执行过程中遇到的异步操作,都先放置到事件队列中
      • 本题是把:(间隔浏览器最小反应事件内,执行对应的箭头函数),放到事件队列中
      • 浏览器会单独开辟一个定时器线程:监听事件队列中存储的各个定时器的到达时间
      • 只有 GUI 线程空闲下来,才会过来找
  • 5、此时 GUI 渲染线程继续向下执行代码:输出 10

  • 6、遇到循环:循环是同步的,代码中遇到死循环,会中断整个页面的循环或者中断代码的执行

  • 7、继续执行同步代码:输出10

  • 事件循环 EventLoop

    • 8、栈内存中的同步任务代码都执行完了:
      • 去事件队列中找到达时间的任务
      • 把找到的已经到达执行条件的任务,放入到栈中执行(每次只拿回来一个)
      • 还是 GUI 线程执行他
    • 9、等 GUI 执行完,“闲下来”,在去事件队列中找其他到达时间的任务......一直到事件队列被执行完为止

    这个循环查找的过程就是 EventLoop 事件循环

3、三种 CSS 样式的渲染区别

GUI 渲染页面时,当遇到其他请求时的两种处理方法:

  • 让 GUI 线程自己去拿:
    • 在CSS文件没有从服务器加载回来之前,下面的代码不会继续渲染
  • 在开辟一个线程,专门去服务器加载CSS文件:
    • 不用管CSS是否加载回来,GUI线程继续向下渲染

-1).在渲染过程中遇到 <link> 引入式样式 : 异步操作

  • 浏览器会新开辟一个 HTTP 的请求线程,专门去服务器加载 CSS 样式内容
  • 此时 GUI 线程还可以继续向下渲染(不用管 CSS 是否回来)

-2).如果遇到的是 @import 导入式样式 : 同步操作

  • 不会开辟新的线程去加载 CSS ,而是当前线程去加载
  • 这样只要 CSS 没有加载回来,下面的代码都不会继续渲染(阻碍页面渲染)

<link>@import 相比较: link 会提高页面渲染速度

-3).内嵌式

上面虽然说link会提高页面渲染速度 ,但是当 CSS 代码较少的情况下,我们最好采用内嵌式(把CSS 和 HTML 写在一起),这样只要把 HTML 加载回来,CSS 也回来了

任何形式的HTTP请求都一定会有时间和性能的消耗

  • 前提是CSS代码少;
  • 代码多的情况下,如果还是和HTML放在一起,那么第一次请求HTML的速度都会变慢,也就得不偿失了;

四、浏览器渲染页面的步骤

1、生成 DOM 树

渲染了所有的 HTML 标签

  • 转换
    • 通过 HTTP 返还的首先是十六进制的编码字节数据
    • 拿到字节数据后,浏览器会通过内部的机制,把数据转换成我们能看到的代码
  • 令牌
    • 按照 W3C 规范(第五代版本的规范H5)的规则,转换成我们能看懂的标签
  • 词法分析
    • 通过转换后的标签,进行词法解析,生成DOM节点
  • DOM构建
    • 最后通过查找每个DOM节点之间的关系,生成DOM

图片来源:图片摘自网络,如有侵权,联系删除

2、生成 CSSOM 树

请求回来 CSS 后,渲染完 CSS

同生成DOM树一样的过程生成CSSOM

图片来源:图片摘自网络,如有侵权,联系删除

3、DOM 树 + CSSOM 树 => RENDER-TREE(渲染树)

图片来源:图片摘自网络,如有侵权,联系删除

4、 布局(Layout)或 重排/回流(reflow)

按照 RENDER-TREE 在设备的视口中进行结构和位置的相关计算=>布局(Layout)或 重排/回流(reflow)

5、绘制(painting)或 栅格化(rasterizing)

根据渲染树以及回流得到的几何信息,得到节点的绝对像素=>绘制(painting)或 栅格化(rasterizing)

思维导图