《高性能 JavaScript》读书笔记

最后更新:
阅读次数:

加载和执行

  • 多数浏览器使用单一进程来处理用户界面(UI)刷新和 JavaScript 脚本执行。(JS 引擎线程与 GUI 渲染线程是互斥的

JavaScript 和 UI 共享同一进程的部分原因是它们之间互相访问频繁。

浏览器在解析到 body 标签之前,不会渲染页面的任何部分。<script> 标签(不管是内联的还是外链的)的每次出现都会让页面停止渲染直到脚本下载、解析和执行完毕。所以把脚本放到页面顶部会导致明显的延迟,通常表现为显示空白页面。

  • 推荐将所有的 script 标签尽可能放到 body 标签的底部: 因为脚本会阻塞页面其他资源的下载,会阻塞页面渲染。

  • 减少页面中外链脚本文件的数量: 这样可以减少 HTTP 请求数,并且会减少脚本执行导致的延迟时间。

script 标签的 defer 和 async 特性的相同点是它们都是采用并行下载脚本,在下载过程中不会对页面产生阻塞,区别在于执行时机,async 是加载完成后自动执行,而 defer 需要等待页面加载完成后执行。(defer 和 async 只作用于有 src 属性的 script 标签)

数据存取

  • 函数在访问某个变量或属性时会在原型链(访问对象的属性)或作用域链(访问外部变量)产生搜索这个变量或属性的过程,正是这个搜索过程影响了性能。因此如果这个变量或属性被访问多次,最好使用局部变量进行缓存。

DOM

  • 减少访问 DOM 的次数
  • 使用局部变量缓存需要被多次访问的 DOM 元素或属性

重绘(repaint)和重排(reflow)

  • DOM 树:表示页面结构
  • 渲染树:表示 DOM 节点如何显示
  • 当页面布局和元素几何属性改变时就需要重排,下面是几种常见的情况

    • 添加或删除可见的 DOM 元素
    • 元素位置改变
    • 元素尺寸改变(包括 margin、padding、border 等的改变)
    • 内容改变(比如文本内容改变)
    • 浏览器窗口尺寸改变
  • 减少重绘和重排的次数

  • 如果要修改 DOM,可通过先构建好修改的子树,再一次性插入 DOM 来减少重绘和重排的次数。(可以使用文档片段 document.createDocumentFragment()

    • 文档片段的设计初衷就是为了更便捷地更新和移动 DOM 节点
let fragment = document.createDocumentFragment();

let p = document.createElement("p");
p.textContent = "p1p1p1p1p1p1p1";

let div = document.createElement("div");
div.textContent = "divdivdivdividiv";

fragment.appendChild(p);
fragment.appendChild(div);
document.body.appendChild(fragment);
  • 涉及到动画时,让元素在动画期间使用绝对定位脱离文档流可以避免页面中的大部分重排
  • 使用事件委托来减少事件处理器的数量

算法和流程控制

  • 条件数量越大,使用 switch 语句,而不是 if-else 语句
  • 优化 if-else 语句:将最可能出现的条件放在语句最前面