几个 JavaScript 性能优化小 Tip

4,722 阅读5分钟

本文翻译自 John Au-Yeung 的 JavaScript Best Practices — Performance,请参考原文阅读

像任何其他编程语言一样,JavaScript 也有自己的最佳实践列表,以使程序更易于阅读和维护。JavaScript 有很多棘手的部分,因此应避免某些降低代码质量的做法。通过遵循最佳实践,我们可以创建优雅且易于管理的代码,让任何人都可以轻松使用。

在本文中,我们将探讨提高应用程序性能的方法,包括将数据缓存在变量中,使用最快的方法循环遍历变量,减少 DOM 访问和页面上的元素,并推迟脚本加载。

减少对变量和属性的访问

我们应该减少访问应用程序中变量和对象属性的次数。

这是因为每次执行此操作时,CPU 都必须一次又一次地访问内存中的项目以计算其结果。

因此,我们应该尽可能少地这样做。

例如,对于一个循环,不应像下面这样:

for(let i = 0; i < arr.length; i++) {
}

而应该写成:

let length = arr.length;
for (let i = 0; i < length; i++) {

}

这样,arr.length 在我们的循环中仅被引用一次,而不是在每次迭代中都对其进行访问。

循环遍历变量的最快方法

在 JavaScript 中,有多种方法遍历可迭代对象。一种是老的 for 循环,其他方法包括 for...of 循环,数组的 forEach 方法。map 和 filter 操作也会遍历数组。还有 while 循环。

在运行循环的所有方式中,for 循环是最快的方式,无论是否像上面一样缓存 length,for 循环都是如此。但是,缓存 length 有时会使循环执行得更好。

一些浏览器引擎在不缓存 length 属性的情况下优化了 for 循环。

递减索引的 whil e循环比 for 循环慢大约 1.5 倍。

使用 forEach 循环的速度比 for 循环慢 10 倍,因此最好避免使用它,尤其是对于大型数组。

我们可以在这里看到结果。

减少 DOM 访问

访问 DOM 是一项昂贵的操作,因为浏览器必须从网页中获取元素,然后从中创建一个对象并返回它。

为了减少 DOM 访问,如果我们需要多次操作 DOM Node 对象,则应该将其赋值给变量。

例如,如果我们有以下 HTML,并且希望在几秒钟后为其设置一些文本:

<p id='foo'>
</p>

我们可以编写以下代码来做到这一点:

const setText = (element, textContent) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      element.textContent = textContent;
      resolve();
    }, 3000)
  })
}
(async () => {
  const foo = document.querySelector('#foo');
  await setText(foo, 'foo');
  await setText(foo, 'bar');
  await setText(foo, 'baz');
})();

在上面的代码中,我们有一个函数来获取我们要操作的 HTML 元素以及要设置的文本内容。

setText 函数返回一个 promise,并将在 3 秒后将文本设置为给定元素。

然后我们有一个 async 函数来设置文本 3 次。核心部分是我们在每次调用时都将元素的引用传递给它。这样,我们不必每次从网页上获取元素,这是一项昂贵的操作。

减少DOM大小

DOM 树渲染起来很慢。因此,我们必须减小树的大小。

这个别无选择,只能使我们的网页尽可能简单。

DOM 较小时,由于查找内容较少,因此可以使用 querySelector,getElementById 或 getElementsByTagName 之类的方法更快地搜索元素。

此外,由于加载的内容更少,因此页面渲染性能也会提高。对于手机和平板电脑等速度较慢的设备尤其如此。

不要声明不必要的变量

每次我们声明变量时,浏览器都必须为变量分配存储空间。因此,为了减少内存使用,我们不应该声明太多变量。

例如,如果我们有以下 HTML:

<div id='foo'>
  <p>
  </p>
</div>

我们想设置 p 元素的文本内容,我们不应该这样写:

const foo = document.querySelector('#foo');
const p = foo.querySelector('p');
p.textContent = 'foo';

因为我们这里有 2 个变量,这意味着我们的计算机必须额外存储 2 个 JavaScript 变量的值。

我们可以通过编写以下代码来减少变量声明:

document.querySelector('#foo p').textContent = 'foo';

如我们所见,我们可以使用 querySelector 方法通过 CSS 选择器选择任何内容。这意味着我们应该使用此方法和相关的 querySelectorAll 方法来选择元素,因为它们都可以使用 CSS 选择器来选择任何 HTML 元素节点。

延迟脚本的加载 加载 JavaScript 文件是一项昂贵的操作。浏览器必须下载文件,解析内容,然后将其转换为机器代码并运行。

浏览器下载一个文件,同时会阻止其他任何操作。

因此,我们应该尽可能地延迟它。我们可以通过将 script 标记放在末尾来实现。另外,我们可以在 script 标签上使用 defer 属性来执行此操作。

另外,我们可以在页面加载后通过动态创建 script 元素并按如下所示运行脚本:

window.onload = () => {
  const element = document.createElement("script");
  element.src = "https://code.jquery.com/jquery-1.12.4.min.js";
  document.body.appendChild(element);
};

页面加载后,想加载任何内容都可以使用此脚本的加载方法。

小结

我们可以通过做一些事情来加快页面速度。首先,我们可以将数据缓存在变量中,因此我们不必重复访问它们。然后,我们可以使用 for 循环更快地遍历项目。

另外,我们可以减小 DOM 大小以减少需要加载的项目。我们还可以通过将 DOM 对象分配给变量来在其代码中缓存它们。

我们也不应声明不必要的变量,并且应尽可能推迟脚本的加载,以免卡住我们的浏览器。