meface/docs/article/web/js/browser.md

6.1 KiB
Raw Blame History

title date author tags categories
浏览器的组成 2020-11-20 ac
JavaScript
Web

浏览器加载网页时会去加载和执行JavaScript脚本和CSS样式文件实现网页各种动态效果。

浏览器的组成

核心两大部分渲染引擎和JavaScript解释器JavaScript引擎它们是互斥的不能同时运行。

JavaScript 引擎

主要作用是,读取网页中的 JavaScript 代码,对其处理后运行。 JavaScript 是一种解释型语言,也就是说,它不需要编译,由解释器实时运行。

  • 优点:是运行和修改都比较方便,刷新页面就可以重新解释;
  • 缺点:是每次运行都要调用解释器,系统开销较大,运行速度慢于编译型语言。

脚本的执行顺序由它们在页面中的出现顺序决定,这是为了保证脚本之间的依赖关系不受到破坏。

通常会将脚本文件都放在网页尾部加载,因为正常的网页加载流程:

  1. 浏览器一边下载 HTML 网页,一边开始解析。也就是说,不等到下载完,就开始解析。
  2. 解析过程中,浏览器发现<script>元素,就暂停解析,把网页渲染的控制权转交给 JavaScript 引擎。
  3. 如果<script>元素引用了外部脚本,就下载该脚本再执行,否则就直接执行代码。
  4. JavaScript 引擎执行完毕,控制权交还渲染引擎,恢复往下解析 HTML 网页。

浏览器一般有限制同时最多下载620个资源即最多同时打开的 TCP 连接有限制,这是为了防止对服务器造成太大压力。如果是来自不同域名的资源,就没有这个限制。所以,通常把静态文件放在不同的域名之下,以加快下载速度。

JS脚本的加载

浏览器加载JS脚本主要通过<script>标签来加载和解析外部脚本或嵌入的JS代码。

<script>标签可以添加一些属性来调节脚本的加载。

  • defer属性浏览器发现<script>标签有defer属性会继续往下解析HTML同时并行下载脚本等解析完HTML页面后再执行下载好的JS代码
  • async属性浏览器发现<script>标签有defer属性会继续往下解析HTML同时并行下载脚本等到下载完后如果HTML页面没有解析完会暂停开始执行下载的脚本等执行完再恢复解析HTML页面。

对于type属性是<script>标签来指定脚本类型的,值为:text/javascript(默认)或application/javascript。如果是其它值,浏览器不会执行其中的代码。

渲染引擎

主要作用是,将网页代码渲染为用户视觉可以感知的平面文档。

不同的浏览器有不同的渲染引擎:

  • FirefoxGecko 引擎
  • SafariWebKit 引擎
  • ChromeBlink 引擎
  • IE: Trident 引擎
  • Edge: EdgeHTML 引擎

渲染引擎处理网页,通常分成四个阶段(渲染机制

  1. 解析代码HTML 代码解析为 DOMCSS 代码解析为 CSSOMCSS Object Model
  2. 对象合成:将 DOM 和 CSSOM 合成一棵渲染树render tree
  3. 布局计算出渲染树的布局layout流式布局模型Flow Based Layout
  4. 绘制:将渲染树绘制到屏幕。

以上四步并非严格按顺序执行,往往第一步还没完成,第二步和第三步就已经开始了。所以,会看到这种情况:网页的 HTML 代码还没下载完,但浏览器已经显示出内容了。

有了 RenderTree,就知道了所有节点的样式,然后计算它们在页面上的大小和位置,最后把节点绘制到页面上。

重流|重绘

渲染树转换为网页布局称为“布局流”flow布局显示到页面的这个过程称为“绘制”paint。它们都具有阻塞效应并且会耗费很多时间和计算资源。

页面生成以后脚本操作和样式表操作都会触发“重流”reflow和“重绘”repaint。用户的互动也会触发重流和重绘比如设置了鼠标悬停a:hover)效果、页面滚动、在输入框中输入文本、改变窗口大小等等。

重流和重绘并不一定一起发生,重流必然导致重绘,重绘不一定需要重流。比如改变元素颜色,只会导致重绘,而不会导致重流;改变元素的布局,则会导致重绘和重流

如何较少重绘和重流

  1. 使用 transform 替代 top
  2. 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回 流(改变了布局
  3. 避免使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。
  4. 尽可能在 DOM 树的最末端改变 class重流是不可避免的但可以减少其影 响。尽可能在 DOM 树的最末端改变 class可以限制了重流的范围使其影响 尽可能少的节点。
  5. 避免设置多层内联样式CSS 选择符从右往左匹配查找,避免节点层级过多。尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽 量少的添加无意义标签,保证层级扁平。
  6. 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上,避免影响其他元 素的布局,这样只是一个重绘,而不是重流。

浏览器优化

现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即 16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。

主要包括以下属性或方法:

  1. offsetTop、offsetLeft、offsetWidth、offsetHeight
  2. scrollTop、scrollLeft、scrollWidth、scrollHeight
  3. clientTop、clientLeft、clientWidth、clientHeight
  4. width、height
  5. getComputedStyle()
  6. getBoundingClientRect()

所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。

参考文章

[1] 浏览器环境概述 https://wangdoc.com/javascript/bom/engine.html