文章

High Performance JavaScript 即时笔记
2017/12/19

脚本位置

  • <script> 标签每次出现都霸道地让页面等待脚本的解析和执行。无论当前的 JavaScript 代码是内嵌的还是包含在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成。
  • 请记住,浏览器在解析到 <body> 标签之前,不会渲染页面的任何部分。把脚本放到页面顶部将会导致明显的延迟,通常表现为显示空白页面。
  • 当加载两个或以上 <script> 脚本时,从 script1.js 下载完成到 script2.js 开始下载前存在一个延时,这段时间正好是 script1.js 的执行过程。每个文件必须等到前一个文件下载并执行完成才会开始下载。现在的浏览器大多允许并行下载 JavaScript 文件。

组织脚本

  • 由于每个 <script> 标签初始下载都会阻塞页面渲染,所以减少页面包含的 <script> 标签数量有助于改善这一情况。
  • 把一段内嵌脚本放在引用外链样式表的 <link> 标签之后会导致页面阻塞去等待样式表的下载。这样做是为了确保内嵌脚本在执行时获得最精准的样式信息。因此,不要把内嵌脚本紧跟在 <link> 标签后面。
  • 考虑到 HTTP 请求会带来额外的性能开销,因此下载单个 100KB 的文件将比下载 4 个 25KB 的文件更快。也就是说,减少页面中外链脚本文件的数量将会改善性能。你可以把多个文件合并成一个,这样只需要引用一个 <script> 标签。

延迟脚本

  • HTML 4 为 <script> 标签定义了一个扩展属性:defer。Defer 属性指明本元素所含的脚本不会修改 DOM,因此代码能安全的延迟执行。(当脚本内容不含修改 DOM 操作时用 defer。)
  • 带有 Defer 属性的 <script> 标签可以放置在文档的任何位置。对应的 JavaScript 文件将在页面解析到 <script> 标签时开始下载且可以与页面中的其他资源并行下载,但并不会执行,直到 DOM 加载完成才会执行。
  • 执行优先等级 普通 script > Defer > window.onload

动态脚本元素

基本原理

var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file1.js";
document.getElementsByTagName("head"[0].appendChild(script);
  • 这个新创建的 <script> 元素加载了 file1.js 文件。文件在该元素被添加到页面时开始下载。这个技术的重点在于:无论何时启动下载,文件的下载和执行不会阻塞页面其他进程。
  • 动态脚本加载凭借着它在跨浏览器兼容性和易用的优势,成为最通用的无阻塞加载解决方案。

XHR 脚本注入

  • 这种方法的主要优点是,你可以下载 JavaScript 代码但不立即执行。由于代码是在 <script> 标签之外返回的,因此他下载后不会自动执行。另一个优点是,兼容性好。
  • 这种方法的局限性是 JavaScript 必须与所请求页面处于相同的域,这意味着 JavaScript 文件不能从 CDN 下载。

条件语句

  • 使用 if-else 还是 switch,最流行的方法是基于条件的数量来判断,条件数量越大,越倾向于使用 switch 而不是 if-else
  • 事实证明,大多数情况下 switchif-else 运行的要更快,但只有当条件数量很大时才快的明显。
  • 优化 if-else 的目标是:最小化到达正确分支前所需判断的条件数量。最简单的优化方法是确保最可能出现的条件放在首位。if-else 中的条件语句应该总是按照从最大概率到最小概率的顺序排列,以确保运行速度最快。

DOM 编程

  • 尽管 DOM 是个与语言无关的 API,它在浏览器中的接口却是用 JavaScript 实现的。
  • 两个相互独立的功能只要通过接口彼此链接,就会产生消耗。
  • 修改元素则更为昂贵。
  • 访问 DOM 的次数越多,代码运行的速度越慢。因此一般经验法则是:减少访问 DOM 的次数,把运算尽量留在 ECMAScript 这一端处理。
  • 在选择多个 DOM 元素时 querySelectorAll()getElementById()getElementsByTagName() 更快。