浏览器重绘/回流

问题描述

有很多关于这个的文章,至少在过去的几个小时里我一直在谷歌搜索和阅读,但我很难找到我需要的真正基本的、菜鸟的答案。我正在尝试了解 webGl 中的动画循环以及 React。

基本上,浏览器是否会在不重新绘制整个屏幕的情况下重新绘制特定元素?回流是否总是刷新整个屏幕?使用刷新按钮手动刷新窗口时发生的情况与回流或重绘之间究竟有什么区别?我知道这项技术已经存在一段时间了,但我之前从未真正深入研究过。

我只是想了解 webGL 代码如何在画布元素上设置动画以及 React 如何更改屏幕上的元素,而无需重新加载整个屏幕。我已经阅读了 requestAnimationFrame 以及 React 如何捆绑和差异虚拟 dom 更改,减少重新渲染请求的数量,但我的问题更多是关于整个窗口重新加载,而不是仅重新渲染单个组件。我正在使用 gatsby/react 和 babylonjs 构建一个网站,并试图围绕基本概念进行思考。谢谢。

解决方法

浏览器的功能有些不确定。你给它 HTML 元素,它会以某种方式在屏幕上绘制它们。它如何优化该过程是未定义的,所定义的只是结果应该是什么样的。我说“有点”是因为即使是像 <p>Hello world</p> 这样的简单元素在不同浏览器上的呈现方式也会不同,在不同操作系统上的同一浏览器上或在同一操作系统上的同一浏览器中,但具有不同的操作系统设置等。

通常,浏览器会构建一个称为 DOM 的节点树(元素及其内容)。然后它遍历那棵树并构建它需要的任何东西来应用 CSS,然后渲染这些元素。大多数浏览器会尝试在该过程中的各个点缓存数据,这样如果页面上的某些内容发生变化,他们就不必从头开始计算所有内容。示例可能包括他们生成一个字形(字母的像素),将这些像素存储在某处,下次他们需要以相同大小绘制字母时,他们可以只使用他们已经生成的像素,而不必从字体中光栅化该字母定义。

浏览器是否重绘特定元素而不重绘整个屏幕?

这取决于浏览器。

回流是否总是刷新整个屏幕?

这取决于浏览器。如果浏览器有办法确定它只需要计算树的某个分支的部分回流,那么它可能不必刷新整个屏幕。

当您使用刷新按钮手动刷新窗口时发生的情况与回流或重绘之间究竟有什么区别?

刷新窗口就像杀死一个程序并从头开始重新运行它。所有数据都必须从网络或缓存中重新加载,文本被解析为元素等。

回流是计算所有元素所属的位置、单词或元素的环绕位置、它们的大小。

重绘正在绘制元素。无需回流即可重绘。

webGL 代码如何在画布元素上动画

画布只是一个像素矩形,类似于 <img>。不同之处在于您可以使用多种 API 之一来影响这些像素(“2d”、“webgl”、“webgl2”、“webgpu”等)

当您更改这些像素时,浏览器知道需要重新绘制 <canvas> 元素。它如何重新绘制取决于浏览器,但至少必须遵循规范的规则,例如 <canvas> 就像几乎所有元素一样,应用了 CSS(它可能有边框,背景图像/颜色/图案、圆角等......)。元素相互叠加,因此您可能在画布前面有元素,也可能在画布后面有元素。

就像我上面说的,浏览器绘制元素所做的事情是未定义的,但你当然可以想象,如果它能够找出唯一改变的是画布的内容,并且画布前面没有元素,并且画布后面没有任何东西,并且画布是不透明的,那么它可能只是重新绘制画布区域。

不过这种情况很少见。例如,大多数 three.js examples 都有位于画布顶部的文本(示例的标题)。许多还具有 FPS 计。有些有一个下拉用户界面。所有这些都是在画布上绘制的,因此至少,必须将画布的新内容绘制到窗口中,然后必须在其上呈现其他元素。

同样,这取决于浏览器。它可以使用软件渲染逐个像素地绘制这些元素,或者它可能已将这些元素的内容存储在纹理中,并使用 GPU 在顶部绘制为四边形。

React 如何在不重新加载整个屏幕的情况下更改屏幕上的元素

我不确定您所说的重新加载是什么意思。 React 保持自己的“虚拟 DOM”。然后它尝试将虚拟 DOM 中的更改应用到实际的浏览器 DOM。如果某些元素不需要更改,则这些元素不会受到影响。

从浏览器的 POV 来看,没有什么不同。浏览器看到的只是 DOM。如果您对 DOM 进行更改(使用 React 或其他任何方式),那么一旦 your current event exits,浏览器将安排一个任务来遍历 DOM 并重新绘制页面(使用优化重新计算/重新绘制页面)少绘制取决于浏览器)。