最佳实践

28.2 性能

28.2.1 作用域意识
第 4 章讨论过 JavaScript 作用域的概念,以及作用域链的工作原理。随着作用域链中作用域数量的
增加,访问当前作用域外部变量所需的时间也会增加。访问全局变量始终比访问局部变量慢,因为必须
遍历作用域链。任何可以缩短遍历作用域链时间的举措都能提升代码性能。

  1. 避免全局查找
    改进代码性能非常重要的一件事,可能就是要提防全局查询。全局变量和函数相比于局部值始终是
    最费时间的,因为需要经历作用域链查找。来看下面的函数:
    function updateUI() {
    let imgs = document.getElementsByTagName(“img”);
    for (let i = 0, len = imgs.length; i < len; i++) {
    imgs[i].title = ‘${document.title} image KaTeX parse error: Expected 'EOF', got '}' at position 8: {i}'; }̲ let msg = doc…{doc.title} image ${i}’;
    }
    let msg = doc.getElementById(“msg”);
    msg.innerHTML = “Update complete.”;
    }
    这里先把 document 对象保存在局部变量 doc 中。然后用 doc 替代了代码中所有的 document。
    这样调用这个函数只会查找一次作用域链,相对上一个版本,肯定会快很多。
    因此,一个经验规则就是,只要函数中有引用超过两次的全局对象,就应该把这个对象保存为一个
    局部变量。

28.2.2 选择正确的方法
与其他语言一样,影响性能的因素通常涉及算法或解决问题的方法。经验丰富的开发者知道用什么
方法性能更佳。通常很多能在其他编程语言中提升性能的技术和方法同样也适用于 JavaScript。

  1. 避免不必要的属性查找
    在计算机科学中,算法复杂度使用大 O 表示法来表示。最简单同时也最快的算法可以表示为常量值
    或 O(1)。然后,稍微复杂一些的算法同时执行时间也更长一些。下表列出了 JavaScript 中常见算法的类型。最佳实践_第1张图片
    常量值或 O(1),指字面量和保存在变量中的值,表示读取常量值所需的时间不会因值的多少而变化。
    读取常量值是效率极高的操作,因此非常快。来看下面的例子:
    let value = 5;
    let sum = 10 + value;
    console.log(sum);
    以上代码查询了 4 次常量值:数值 5、变量 value、数值 10 和变量 sum。整体代码的复杂度可以认
    为是 O(1)。 在 JavaScript 中访问数组元素也是 O(1)操作,与简单的变量查找一样。因此,下面的代码与前面的
    例子效率一样:
    let values = [5, 10];
    let sum = values[0] + values[1];
    console.log(sum);
    使用变量和数组相比访问对象属性效率更高,访问对象属性的算法复杂度是 O(n)。访问对象的每个
    属性都比访问变量或数组花费的时间长,因为查找属性名要搜索原型链。简单来说,查找的属性越多,
    执行时间就越长。来看下面的例子:
    let values = { first: 5, second: 10 };
    let sum = values.first + values.second;
    console.log(sum);
    这个例子使用两次属性查找来计算 sum 的值。一两次属性查找可能不会有明显的性能问题,但几百
    上千次则绝对会拖慢执行速度。
    特别要注意避免通过多次查找获取一个值。例如,看下面的例子:
    let query = window.location.href.substring(window.location.href.indexOf("?"));
    这里有 6 次属性查找:3 次是为查找 window.location.href.substring(),3 次是为查找
    window.location.href.indexOf()。通过数代码中出现的点号数量,就可以知道有几次属性查找。
    以上代码效率特别低,这是因为使用了两次 window.location.href,即同样的查找执行了两遍。
    只要使用某个 object 属性超过一次,就应该将其保存在局部变量中。第一次仍然要用 O(n)的复杂
    度去访问这个属性,但后续每次访问就都是 O(1),这样就是质的提升了。例如,前面的代码可以重写为
    如下:
    let url = window.location.href;
    let query = url.substring(url.indexOf("?"));
    这个版本的代码只有 4 次属性查找,比之前节省了约 33%。在大型脚本中如果能这样优化,可能就
    会明显改进性能。
    通常,只要能够降低算法复杂度,就应该尽量通过在局部变量中保存值来替代属性查找。另外,如
    果实现某个需求既可以使用数组的数值索引,又可以使用命名属性(比如 NodeList 对象),那就都应
    该使用数值索引。

28.2.4 优化 DOM 交互
在所有 JavaScript 代码中,涉及 DOM 的部分无疑是非常慢的。DOM 操作和交互需要占用大量时间,
因为经常需要重新渲染整个或部分页面。此外,看起来简单的操作也可能花费很长时间,因为 DOM 中
携带着大量信息。理解如何优化 DOM 交互可以极大地提升脚本的执行速度。

  1. 实时更新最小化
    访问 DOM 时,只要访问的部分是显示页面的一部分,就是在执行实时更新操作。之所以称其为实
    时更新,是因为涉及立即(实时)更新页面的显示,让用户看到。每次这样的更新,无论是插入一个字
    符还是删除页面上的一节内容,都会导致性能损失。这是因为浏览器需要为此重新计算数千项指标,之
    后才能执行更新。实时更新的次数越多,执行代码所需的时间也越长。反之,实时更新的次数越少,代
    码执行就越快。来看下面的例子

你可能感兴趣的:(JavaScript)