浏览器渲染原理 - 输入url 回车后发生了什么

目录

  • 渲染时间点
  • 渲染流水线
    • 1,解析(parse)HTML
      • 1.1,DOM树
      • 1.2,CSSOM树
      • 1.3,解析时遇到 css 是怎么做的
      • 1.4,解析时遇到 js 是怎么做的
    • 2,样式计算 Recalculate style
    • 3,布局 layout
    • 4,分层 layer
    • 5,绘制 paint
    • 6,分块 tiling
    • 7,光栅化 raster
    • 8,画 draw
  • 常见面试题
    • 什么是 reflow
    • 什么是 repaint
    • 为什么 transform 效率高

在上一篇文章中,介绍了 浏览器的事件循环,其中提到了浏览器的进程模型。那浏览器是如何渲染页面的呢?

渲染时间点

浏览器会通过网络进程中的线程来通信,获取到 html 数据后生成渲染任务,发送给消息队列。

渲染主线程会执行渲染任务。整个渲染流程:把 html 字符串解析为像素点信息,再交给 GPU来渲染后在页面中展示。

在这里插入图片描述

渲染流水线

在这里插入图片描述

每个阶段都有明确的输入输出,上个阶段的输出会成为下个阶段的输入。形成一套完整的流水线。

1,解析(parse)HTML

会将 html 字符串解析为 2个树。因为字符串不好操作,对象更容易处理。

1.1,DOM树

也就是 document 对象。可以在控制台通过console.dir(document) 展示对象结构。
在这里插入图片描述

1.2,CSSOM树

包括:

  • <style> 内部样式
  • <link> 外部样式
  • style="" 内联样式
  • 浏览器默认样式表

在这里插入图片描述

注意,这里的 CSSOM树 ≠ document.styleSheets。因为 document.styleSheets 只包括内部样式外部样式,每写一个 <style><link> 就会多一个 CSSStyleSheet 样式表:

在这里插入图片描述

举例说明:

<html><head><style>body h1 {color: red;font-size: 3em;}div p {margin: 1em;color: blue;}</style></head><body><h1>下雪天的夏风</h1><div><p>求关注</p></div></body>
</html>

在这里插入图片描述

可以看到:

  • CSSStyleSheet 样式表
    • CSSStyleRule 规则对象
      • selectorText 选择器
      • style 样式(键值对)

另外,CSSStyleSheet 样式表是可以直接通过 js 操作的。

举例:通过 js 给页面所有 div 添加 border

document.styleSheets[0].addRule('div', 'border: 1px solid !important')

这样添加样式的方式,一般框架用的多。最终样式不会在内联样式中展现。

1.3,解析时遇到 css 是怎么做的

渲染主线程遇到 css 时,会启动一个预解析线程,让它来率先下载和解析 css。渲染主线程继续解析 html。

预解析线程会快速浏览,如果遇到外部样式link ,会通知网络线程来下载 css,下载完成后进行“解析”完成后交给渲染主线程。

并不是真正的解析,只是做一些前期工作,最终生成 CSSOM 树还是由渲染主线程来完成。

所以,css 代码不会阻塞解析 HTML。

在这里插入图片描述

1.4,解析时遇到 js 是怎么做的

没有生成所谓的 js 树,是因为 js 只需要执行一遍即可。DOM树和CSSOM树作为解析 HTML 的输出,后续还会有其他的操作。

渲染主线程遇到内部 js 时,直接启动 V8 引擎执行即可;遇到外部 js 时,会启动一个预解析线程,让它来下载 js,渲染主线程暂停

预解析线程会通知网络线程来下载 js,下载完成后再交给渲染主线程来执行。执行完继续解析 HTML。

这样做的原因:DOM 树是边解析边生成的,而 js 代码可能会修改之前已解析好的内容。

所以,js 代码会阻塞解析 HTML。

在这里插入图片描述

2,样式计算 Recalculate style

遍历DOM树,计算每个节点的最终样式 Computed Style。

这一过程,许多预设值会变成绝对值,比如 red 变为 rgb(255,0,0);相对单位变为绝对单位,比如rem 变为 px

最终会得到1个带有最终样式的 DOM 树。
在这里插入图片描述

可以在浏览器的 computed 窗口中,或使用 getComputedStyle() 查看某个元素的最终样式。

3,布局 layout

遍历DOM树的每个节点,根据 css 属性值计算每个节点的几何信息(尺寸,相对包含块的位置),生成一个 layout 树。

注意到 DOM 树和 layout 树不一定一一对应。
在这里插入图片描述
举例1:diaplay:none 的元素不会出现在 layout 树中。

问题来了,为什么<head> <link> 等元素默认是隐藏的?因为在浏览器默认样式表中,它们 diaplay:none
在这里插入图片描述
举例2:伪元素的 content 内容在 DOM 树中没有,在 layout 树中有。

在这里插入图片描述
举例3:内容必须在行盒中,行盒和块盒不能相邻。所以在 layout 树中会有匿名块盒

解释:“行级元素”,“块级元素”这些元素指的是 html。但元素的类型是 css 属性决定的。所以称为行盒或块盒。

在这里插入图片描述

4,分层 layer

现在 layout 布局树中每个节点的几何信息,尺寸位置等都明确了。渲染主线程会使用一套策略对整个布局树分层。

目的是提升效率,这样可以让之后页面的修改更新不会影响到其他层。类似 PS 中的图层,修改某一个图层不会影响到其他图层。

可以在浏览器控制台的 Layers 面板查看当前网页的分层信息。
也不会分太多的层,因为会比较占内存。滚动条是单独一层。

在这里插入图片描述

另外,和堆叠上下文有关的 css 属性(transform,opacity)会影响分层的决策。其中 will-change 属性能更大程度的影响分层角色,可能会将设置该属性的元素单独分一层。

因为这个属性会告诉浏览器,我可能会经常变化,浏览器最好掂量下。

5,绘制 paint

分层后,会对每层都生成绘制指令,类似于 canvas 中的 API 一样。其实canvas 用的就是浏览器内核的绘制功能。

指令举例:“笔”移动到 xx 坐标位置,画 100*100 的矩形,并用红色填充等等。

在这里插入图片描述

以上。渲染主线程的工作结束,剩下的步骤交给其他线程来完成。

在这里插入图片描述

6,分块 tiling

将每层都分为多个小的区域,浏览器视窗区域的优先级最高,靠近视窗区域的优先级次之。
在这里插入图片描述

分块逻辑:渲染主线程每个图层的绘制信息交给合成线程,合成线程又会启动多个分块线程来对每个图层进行分块。

合成线程也属于渲染线程

在这里插入图片描述

7,光栅化 raster

将每个块变成位图,位图就是每个像素点的信息。优先处理靠近视窗的块。

位图就是内存中的二位数组,其中记录了每个像素点的信息。

在这里插入图片描述

此过程会用到GPU来加速,用到显卡。
在这里插入图片描述

8,画 draw

合成线程现在拿到了所有的信息,在画之前还需要确认【指引信息 quad】,也就是位图相对的屏幕在哪里。

注意,之前布局树中的信息是相对于整个页面的。现在需要知道每个块相对于屏幕的位置信息。

步骤:合成线程将指引信息 --> GPU 进程 --> 硬件显卡,由显卡来呈现最终的像素信息。

GPU 做中转的原因是:GPU 是浏览器的进程。合成线程属于渲染进程,它是在沙盒中的,与硬件系统做隔离,提升安全性。所以渲染进程是没有调度系统硬件能力的。

在这里插入图片描述
而 css 中的 transform 属性就是在这一步完成的。这就是 transform 效率高的原因,直接跳过之前所有的步骤。

常见面试题

什么是 reflow

【recalculate layoutBlockFlow 重排】它的本质是重新计算 layout 树

当做了会影响 layout 树的操作后,比如修改几何尺寸相关的信息时,会引起重新计算 layout 树。

在这里插入图片描述

并且,为了避免连续多次的操作导致 layout 树反复计算,浏览器会合并这些操作,当 js 代码完成后统一计算。所以这一步骤是异步的。

同样因为这个原因,当 js 获取布局属性时,可能无法获取到最新的布局信息。

浏览器会在反复权衡下,最终决定获取属性时立即 reflow。

什么是 repaint

它的本质是重新根据分层信息计算了绘制指令

当改变了可见样式,比如颜色等和几何尺寸无关的属性时,就需要重新计算,会从【绘制】这一步骤开始重新执行。

而因为几何尺寸也属于可见样式,所以 reflow 一定会引起 repaint。

在这里插入图片描述

为什么 transform 效率高

因为 transform 既不会影响布局,也不会影响绘制,它只会影响渲染的最后一步【画】。而【画】是在合成线程中,不会影响到渲染主线程。同样无论渲染主线程多忙,也不会影响到 transform。

验证代码如下,当渲染主线程卡死时,transform 不受影响。

<!DOCTYPE html>
<html lang="en"><head><style>.common {width: 50px;height: 50px;background-color: salmon;border-radius: 50%;margin: 10px;}.ball1 {animation: move1 1s alternate infinite;}.ball2 {position: relative;left: 0;animation: move2 1s alternate infinite;}@keyframes move1 {to {transform: translate(100px);}}@keyframes move2 {to {left: 100px;}}</style></head><body><button id="btn">死循环3s</button><div class="common ball1"></div><div class="common ball2"></div><script>btn.addEventListener("click", function () {delay(3000);});function delay(duration) {var start = Date.now();while (Date.now() - start < duration) {}}</script></body>
</html>

效果:
在这里插入图片描述

滚动也是一样的逻辑,如果 js 有一段上面的死循环,并不会影响到滚动。因为只有视窗内元素的位置变了,直接执行【画 draw】这一步骤。

以上。


参考:渡一教育。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/96704.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集群、负载均衡集群、高可用集群简介,LVS工作结构、工作模式、调度算法和haproxy/nginx模式拓扑介绍

一.集群的定义 1.定义 2.分类 &#xff08;1&#xff09;负载均衡集群&#xff08;LBC/LB&#xff09; &#xff08;2&#xff09;高可用集群&#xff08;HAC&#xff09; 二.使用集群的意义 1.高性价比和性能比 2.高可用性 3.可伸缩性强 4.持久和透明性高 三.常见的…

图像去雨-雨线清除-图像处理-(计算机作业附代码)

背景 多年来&#xff0c;图像去雨已经被广泛研究&#xff0c;使用传统方法和基于学习的方法。然而&#xff0c;传统方法如高斯混合模型和字典学习方法耗时&#xff0c;并且无法很好地处理受到严重雨滴影响的图像块。 算法 通过考虑雨滴条状特性和角度分布&#xff0c;这个问…

Mybatis查询数据库返回任意形式的返回结构

Mybatis查询数据库返回任意形式的返回结构 mapper的接口mapper.xml mapper的接口 假如有多个记录&#xff0c;可以将map放到 arraylist里 mapper.xml 主要是通过resultMap定义好映射格式

尼科彻斯定理-C语言/Java

描述 验证尼科彻斯定理&#xff0c;即&#xff1a;任何一个整数m的立方都可以写成m个连续奇数之和。 例如&#xff1a; 1^31 2^335 3^37911 4^313151719 输入一个正整数m&#xff08;m≤100&#xff09;&#xff0c;将m的立方写成m个连续奇数之和的形式输出。&…

vscode远程连接Linux失败,提示过程试图写入的管道不存在(三种解决办法)

vscode报错如下&#xff1a; 一、第一种情况 原因是本地的known_hosts文件记录服务器信息与现服务器的信息冲突了&#xff0c;导致连接失败。 解决方案就是把本地的known_hosts的原服务器信息全部删掉&#xff0c;然后重新连接。 二、第二种情况 在编写配置文件config时&…

RequestRespons

文章目录 Request&Respons1 Request和Response的概述2 Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 获取请求参数的通用方式 2.3 IDEA快速创建Servlet2.4 请求参数中文乱码问题2.4.1 POST请…

stable diffusion基础

整合包下载&#xff1a;秋叶大佬 【AI绘画8月最新】Stable Diffusion整合包v4.2发布&#xff01; 参照&#xff1a;基础04】目前全网最贴心的Lora基础知识教程&#xff01; VAE 作用&#xff1a;滤镜微调 VAE下载地址&#xff1a;C站&#xff08;https://civitai.com/models…

Oracle将与Kubernetes合作推出DevOps解决方案!

导读Oracle想成为云计算领域的巨头&#xff0c;但它不是推出自己品牌的云DevOps软件&#xff0c;而是将与CoreOS在Kubernetes端展开合作。七年前&#xff0c;Oracle想要成为Linux领域的一家重量级公司。于是&#xff0c;Oracle主席拉里埃利森&#xff08;Larry Ellison&#xf…

Lnton羚通关于【PyTorch】教程:torchvision 目标检测微调

torchvision 目标检测微调 本教程将使用Penn-Fudan Database for Pedestrian Detection and Segmentation 微调 预训练的Mask R-CNN 模型。 它包含 170 张图片&#xff0c;345 个行人实例。 定义数据集 用于训练目标检测、实例分割和人物关键点检测的参考脚本允许轻松支持添加…

【环境配置】Windows 10 安装 PyTorch 开发环境,以及验证 YOLOv8

Windows 10 安装 PyTorch 开发环境&#xff0c;以及验证 YOLOv8 最近搞了一台Windows机器&#xff0c;准备在上面安装深度学习的开发环境&#xff0c;并搭建部署YOLOv8做训练和测试使用&#xff1b; 环境&#xff1a; OS&#xff1a; Windows 10 显卡&#xff1a; RTX 3090 安…

STM32 F103C8T6学习笔记9:0.96寸单色OLED显示屏—自由取模显示—显示汉字与图片

今日学习0.96寸单色OLED显示屏的自由取模显示: 宋体汉字比较复杂&#xff0c;常用字符可以直接复制存下来&#xff0c;毕竟只有那么几十个字母字符&#xff0c;但汉字实在太多了&#xff0c;基本不会全部放在单片机里存着&#xff0c;一般用到多少个字就取几个字的模&#xff…

codesys和HMI通讯

codesys可视化有2种&#xff1a; 网页web // 类似于路由器管理那样&#xff0c;登录网页就能操作 本地HMI // 其他品牌的触摸屏 符号配置&#xff1a; 1 编译需要的变量 2 导出XML文件 3 触摸屏软件加载XML文件

从零实战SLAM-第八课(非特征点的视觉里程计)

在七月算法报的班&#xff0c;老师讲的蛮好。好记性不如烂笔头&#xff0c;关键内容还是记录一下吧&#xff0c;课程入口&#xff0c;感兴趣的同学可以学习一下。 --------------------------------------------------------------------------------------------------------…

Eclipse集成MapStruct

Eclipse集成MapStruct 在Eclipse中添加MapStruct依赖配置Eclipse支持MapStruct①安装 m2e-aptEclipse Marketplace的方式安装Install new software的方式安装&#xff08;JDK8用到&#xff09; ②添加到pom.xml 今天拿到同事其他项目的源码&#xff0c;导入并运行的时候抛出了异…

使用 Ansible Galaxy 安装角色

使用 Ansible Galaxy 安装角色 使用 Ansible Galaxy 和要求文件 /home/curtis/ansible/roles/requirements.yml 。从以下 URL 下载角色并安装到 /home/curtis/ansible/roles &#xff1a; http://rhgls.area12.example.com/materials/haproxy.tar 此角色的名称应当为 balancer …

每日一题leetcode--使循环数组所有元素相等的最少秒数

相当于扩散&#xff0c;每个数可以一次可以扩散到左右让其一样&#xff0c;问最少多少次可以让整个数组都变成一样的数 使用枚举&#xff0c;先将所有信息存到hash表中&#xff0c;然后逐一进行枚举&#xff0c;计算时间长短用看下图 考虑到环形数组&#xff0c;可以把首项n放…

Mac鼠标增强工具Smooze Pro

Smooze Pro是一款Mac上的鼠标手势增强工具&#xff0c;可以让用户使用鼠标手势来控制应用程序和系统功能。 它支持多种手势操作&#xff0c;包括单指、双指、三指和四指手势&#xff0c;并且可以自定义每种手势的功能。例如&#xff0c;您可以使用单指向下滑动手势来启动Expos视…

Ant Design Pro 前端脚手架 配置混合导航

Ant Design Pro脚手架 点击查看阅读 混合导航&#xff1a; 顶部导航和侧边栏导航实现联动效果&#xff0c;点击不同的顶部导航按钮会显示对应的子菜单项。 实现点&#xff1a; 1. 路由的配置 菜单展示 我们可以在 route 中进行 menu 相关配置&#xff0c;来决定当前路由是否…

kubernetes(namespace、pod、deployment、service、ingress)

NameSpace NameSpace名称空间 用来隔离资源&#xff0c;但是不隔离网络 使用命令行&#xff1a; kubectl create ns hello #创建 kubectl delete ns hello #删除 kubectl get ns #查看使用配置文件&#xff1a; vi hello.yamlapiVersion: v1 kind: Namespace metadata:name…

Freertos学习

一、概念 实时操作系统&#xff0c;要求一个高的实时性&#xff0c;就不是像在一个死循环中放俩函数了。而是创建俩任务&#xff0c;也叫做俩进程&#xff0c;高速的轮流执行&#xff0c;提高实时性。 堆栈的申请是任务的基础。 二、创建任务 创建任务又两种方式&#xff0c;…