好久没有翻译文章了,最近看到一篇不错的文章,恰好安排上。javascript
原文地址:How JavaScript works: the rendering engine and tips to optimize its performancecss
这是探讨 JavaScript
系列文章的第 11 篇,专门探讨 JavaScript
及其构建组件。识别和描述核心元素的过程当中,咱们还分享了一些在构建 SessionStack
时使用的经验法则。SessionStack
是一个须要强大且高性能的 JavaScript
应用程序,以帮助用户实时发现并重现他们的 Web 应用程序缺陷。html
若是你想阅读系列的其余文章,能够看下面的连接:html5
到目前为止,在咱们以前的 "JavaScript的工做原理" 系列博客文章中,咱们一直专一于JavaScript做为一种语言,其功能,如何在浏览器中执行,如何对其进行优化等。java
可是,在构建 Web 应用程序时,不只仅只是会编写独立运行的 JavaScript 代码。您编写的 JavaScript 代码须要和环境进行交互。了解此环境,和其工做方式以及它的组成将使您可以构建更好的 web 应用程序,并能为后续应用程序发布后可能出现的潜在问题作好充分的准备。 node
那么,咱们来看看浏览器主要由哪些部分组成:git
本文中,咱们将重点介绍渲染引擎,由于它处理 HTML 和 CSS 的解析和可视化,并且大多数 JavaScript 应用程序会一直与之交互。github
渲染引擎主要负责在浏览器屏幕上显示请求的页面。web
渲染引擎能够显示 HTML 和 XML 文件和图像。若是你使用其余的插件,该引擎还能显示不一样类型的文档,如 PDF。编程
与 JavaScript 引擎相似,不一样的浏览器也使用不一样的渲染引擎。下面是一些流行的渲染引擎:
渲染引擎从网络层接收所请求文档的内容。
渲染引擎的第一步是解析 HTML 文档,并将解析的元素转换为DOM 树 中的实际 DOM 节点。
假设你输入了如下文本:
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="theme.css">
</head>
<body>
<p> Hello, <span> friend! </span> </p>
<div>
<img src="smiley.gif" alt="Smiley face" height="42" width="42">
</div>
</body>
</html>
复制代码
该 HTML 文档的 DOM 树看起来像下面这样:
基本上,每一个元素都表示为其直接所包含的全部元素的父节点,而且这是递归进行的。
CSSOM 指的是 CSS 对象模型。当浏览器构建页面的 DOM 时,在 head
部分,遇到引用外部层叠样式表 theme.css
的 link
标签时,预计可能须要这个资源来渲染页面,它就当即为此发送了一个请求。 假设 theme.css
文件包含如下内容:
body {
font-size: 16px;
}
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
复制代码
和 HTML 同样,引擎须要将 CSS 转换成浏览器能够识别的东西— CSSOM。 下面是 CSSOM 树的样子:
你想知道为何 CSSOM 有树形结构吗?当计算页面上任何对象的最终样式集时,浏览器从适用于该节点的最通常规则(例如,若是它是 body 元素的子级,则应用全部 body 的样式)开始,而后经过应用更具体的规则递归地优化计算出的样式。
让咱们来研究一下给出的具体示例。 位于 body 元素中的 span 标签所包含的全部文本,字体大小都是 16px 而且颜色为红色。这些样式是从 body 元素继承的。 若是 span 元素是 p 标签的子元素,则会由于设置了更具体的样式,而不会显示其内容。
另外,请注意,上面的树不是完整的 CSSOM 树,它只显示了样式表中咱们决定重写的样式。每一个浏览器都提供了一组默认的样式,也称为 用户代理样式 — 也就是咱们没有明确提供任何样式时会看到的样式。 咱们的样式只是覆盖了这些默认样式。
HTML 中的视觉指令与 CSSOM 树中的样式数据相结合,用于建立渲染树。
你可能会问什么是渲染树?这是一个可视化元素树,按照它们在屏幕上显示的顺序构建。它是 HTML 和相应的 CSS 的可视化表示。此树的目的是使内容可以按正确的顺序进行绘制。
渲染树中的每一个节点称为渲染器或WebKit中的渲染对象。
这里是上面的 DOM 和 CSSOM 树的渲染器树的样子:
要构造渲染树,浏览器大体执行如下操做:
你能够在这里查看 RenderObject 的源代码(在webkit中):github.com/WebKit/webk…
让咱们来看看这个类的核心内容:
class RenderObject : public CachedImageClient {
// Repaint the entire object. Called when, e.g., the color of a border changes, or when a border
// style changes.
Node* node() const { ... }
RenderStyle* style; // the computed style
const RenderStyle& style() const;
...
}
复制代码
每一个渲染器表明一个一般与某节点的 CSS 盒子相对应的矩形区域。它包含了一些几何信息,如宽,高和位置。
当渲染器被建立并添加到树中时,它是没有位置和大小的。而计算这些值就称为布局。
HTML 使用基于流的布局模型,这意味着它大多数状况下能够一次性计算出几何结构。坐标系是相对于根渲染器的,使用顶部和左侧坐标。
布局是一个递归的过程 — 它从对应于 HTML 文档 <html>
元素的根渲染器开始。布局经过部分或整个渲染器的层级继续递归,为每一个依赖它的渲染器计算几何信息。
根渲染器的位置为0,0
,其尺寸与浏览器窗口(即视区)的可见部分大小相同。
布局过程的开始意味着给每一个节点赋予应该在屏幕中显示的精确坐标。
在此阶段,将遍历渲染器树,并调用渲染器的 paint()
方法在屏幕上显示内容。
绘制能够是全局的或递增的(相似于布局):
paint
事件。操做系统经过一种将多个区域合并为一个区域的智能方式来实现这一点。一般来讲,了解绘制是一个渐进的过程是很是重要的。为了更好的用户体验,渲染引擎会尽量快地将内容显示在屏幕上。它不会等到全部的 HTML 都被解析后才开始构建和绘制渲染树。部份内容将被解析并显示,同时该过程会继续处理来自网络的其他内容项。
当解析器到达 <script>
标签时,将当即解析并执行脚本。在脚本执行以前,将中止对文档的解析,这意味着该过程是同步的。
若是脚本是外部的,那么首先必须从网络中获取它(也是同步的)。在获取完成以前,全部解析都将中止。
HTML5 添加了一个选项,将脚本标记为异步脚本,以便由其余线程解析和执行。
若是你想优化你的应用程序,你须要关注五个主要方面。如下是你能够控制的方面:
JavaScript 常常触发浏览器中的视觉变化。尤为是构建单页应用时。
下面是一些关于你能够优化 JavaScript 的哪些部分来改进渲染的建议:
setTimeout
或 setInterval
进行视觉更新。它们将在帧的某个不肯定时刻调用 “callback”,可能在帧结束时执行。咱们要作的是在帧开始时触发视觉变化而不要错过它。requestAnimationFrame
,setTimeout
,setInterval
中运行它们。经过添加和删除元素,修改属性等更改 DOM 将使浏览器从新计算元素样式,在许多状况下,还会从新计算整个页面或至少部分页面的布局。
要优化渲染,请考虑如下内容:
布局的从新计算对于浏览器来讲可能很是繁重。能够考虑如下方面的优化:
width,height,left,top
等属性以及一般与几何图形相关的属性的更改,都须要布局。因此,尽可能避免改变这些属性。flexbox
。它渲染得更快,能够为你的应用程序创造巨大的性能优点。box.offthesight
是没有问题的。可是,若是在获取前更改了盒子的样式(例如,给元素动态添加一些 CSS 类),浏览器必须先去更改样式,而后再进行布局。这可能很是耗费时间和资源,所以要尽量避免。绘制一般是全部任务中运行时间最长的,所以尽量避免绘制是很是重要的。咱们能够这样作:
渲染是 SessionStack 正常运转的一个重要方面。SessionStack 必须将用户在浏览 Web 应用程序时遇到问题时发生的全部事情从新建立成一个视频。为此,SessionStack 仅利用咱们的库收集的数据:用户事件、DOM更改、网络请求、异常、调试消息等。咱们的播放器通过高度优化,可以正确地渲染和使用全部收集的数据,以便不管从视觉上仍是技术上为用户的浏览器和浏览器中发生的一切提供一个完美像素模拟。
若是你想 试一试 SessionStack,有一个免费的计划。