如何写好 JavaScript (一) ——《高性能 JavaScript》章节总结

来源:互联网 发布:cmm软件内涵 编辑:程序博客网 时间:2024/05/22 00:20

现在当你在写一段JS的时候,往往为了提高性能,会选择压缩和合并,或者使用模块化的加载方式。借助这些插件和工具,我们提升了我们JS的执行性能和优化了加载资源的速度。而且现在我们拥有强大的JS处理引擎,比如Chrome的V8。但是仍然有一部分需要我们关注的地方:DOM交互、网络延迟、JavaScript的阻塞和并发下载等。也就是说除了借助工具和引擎外,更需要我们关注JavaScript的底层性能。

我选取了《高性能 JavaScript》一书中的章节总结,来大概的展示如何编写高性能JavaScript。如果觉得有所帮助,那么非常应该买一本书来仔细读读,每个章节内容都值得学习。值得一提的是本书作者Nicholas C.Zakas也是“红宝书”《JavaScript高级程序设计》一书的作者。大师之作,值得学习。

1、加载和执行(Loading and Execution)

管理浏览器中的JavaScript代码是个棘手的问题,因为代码执行过程会阻塞浏览器的其他进程,比如用户界面绘制。每次遇到<script>标签,页面都必须停下来等待代码下载(如果是外链文件)并执行,然后继续处理其他部分。尽管如此,还是有几种方法能减少JavaScript对性能的影响:

  • </body>闭合标签之前,将所有的<script>标签放到页面的底部。这能确保在脚本执行前页面已经完成了渲染。

  • 合并脚本。页面中的<script>标签越少,加载也就越快,响应也更迅速。无论外链文件还是内嵌脚本都是如此。

  • 有多种无阻塞下载 JavaScript 的方法:

    使用<script>标签的defer属性;

    使用动态创建的<script>元素来下载并执行代码;

    使用XHR对象下载JavaScript代码并注入页面中。

2、数据存取

在JavaScript中,数据存储的位置会对代码整体性能产生重大的影响。数据存储共有4中方式:字体量、变量、数组项、对象成员。它们有着各自的性能特点。

  • 访问字面量和局部变量的速度最快,相反,访问数组元素和对象成员相对较慢。

  • 由于局部变量存在于作用域链的起始位置,因此访问局部变量比访问跨作用域变量更快。变量在作用域链中的位置越深,访问所需的时间就越长。由于全局变量总处在作用域链的最末端,因此访问速度也是最慢的。

  • 避免使用with语句,因为它会改变执行环境作用域链。同样,try-catrch语句中的catch子句也有同样的影响,因此也要小心使用。

  • 嵌套的对象成员会明显影响性能,尽量少访问。

  • 属性或方法在原型链中的位置越深,访问它的速度也越慢。

  • 通常来说,你可以通过把常用的对象成员、数组元素、跨域变量保存在局部变量中来改善JavaScript性能,因为局部变量访问速度更快。

3、DOM编程

访问和操作DOM是现代Web应用的重要部分。但每次穿越连接ECMAScript和DOM两个岛屿之间的桥梁,都会被收取“过桥费”。为了减少DOM编程带来的性能损失,请记住以下几点:

  • 最小化DOM访问次数,尽可能在JavaScript端处理

  • 如果需要多次访问某个DOM节点,请使用局部变量存储它的引用

  • 小心处理HTML集合,因为它实时连系着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,建议把它拷贝到一个数组中。

  • 如果可能的话,使用速度更快的API,比如querySelectorAll()和firstElementChild。

  • 要留意重绘和重排;批量修改样式时,“离线”操作DOM树,使用缓存,并减少访问布局信息的次数。

  • 动画中使用绝对定位,使用拖放处理。

  • 使用事件委托来减少事件处理器的数量。

4、算法和流程控制

JavaScript和其他编程语言一样,代码的写法和算法会影响运行时间。与其他语言不同的是,JavaScript可用资源有限(注),因此优化技术更为重要。

  • for、while和do-while循环性能特性相当,并没有一种循环类型明显快于或慢于其他类型。

  • 避免使用for-in循环,除非你需要遍历一个属性数量未知的对象。

  • 改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代数。

  • 通常来说,switch总是比if-else快,但并不总是最佳解决方案。

  • 在判断条件较多时,使用查找表比if-else和switch更快。

  • 浏览器的调用栈大小限制了递归算法在JavaScript中的应用;栈溢出错误会导致其他代码中断运行。

  • 如果你遇到栈溢出错误,可将方法改为迭代算法,或使用Memoization来避免重复计算。

运行的代码数量越大,使用这些策略所带来的性能提升也就越明显。

5、字符串和正则表达式

  • 当连接数量巨大或尺寸巨大的字符串时,数组项合并是唯一在IE7及更早版本中性能合理的方法。

  • 如果不需要考虑IE7及更早版本的性能,数组项合并是最慢的字符串连接方法之一。推荐使用简单的+和+=操作符替代,避免不必要的中间字符串。

  • 回溯既是正则表达式本应快速匹配的地方,但因为某些特殊的字符串匹配动作导致运行缓慢甚至浏览器崩溃。避免这个问题的办法是:使相邻的字元互斥,避免嵌套量词对同一字符串的相同部分多次匹配,通过重复利用预查的原子组去除不必要的回溯。

  • 提高正则表达式效率的各种技术手段会有助于正则表达式更快地匹配,并在非匹配位置上花更少的时间

  • 正则表达式并不总是完成工作的最佳工具,尤其当你只搜索字面字符串的时候。

  • 尽管有许多方法可以去除字符串的首尾空白,但使用两个简单的正则表达式(一个用来去除头部空白,另一个用来去除尾部空白)来处理大量字符串内容能提供一个简洁而跨浏览器的方法。从字符串末尾开始循环向前搜索第一个非空白字符,或者将次技术同正则表达式结合起来,会提供一个更好的替代方案,它很少受到字符串长度影响。

原创粉丝点击