高性能的JavaScript

103 阅读8分钟
减少JavaScript对性能的影响
  • 闭合之前,将所有的
  • 合并脚本,页面中的
  • 有多种无阻塞下载JavaScript的方法
    • 使用
    • 使用动态创建的
    • 使用XHR对象下载JavaScript代码并注入页面中
数据存取

数据存储共有4种方式:字面量、变量、数组项、对象成员

  • 访问字面量和局部变量的速度最快,访问数组元素和对象成员相对较慢
  • 由于局部变量存在与作用域链的起始位置,因此访问局部变量比访问跨作用域变量更快,变量在作用域链中的位置越深,访问所需的时间越长。由于全局变量总处在作用域链的最末端,因此访问速度也是最慢的
  • 避免使用with语句,因为它会改变执行环境作用域链。同样,try-catch语句中的catch子句也会有同样的影响
  • 嵌套的对象成员会明显影响性能,尽量少用
  • 属性或方法在原型链中的位置越深,访问他的速度就越慢
  • 通常来说,你可以通过把常用的对象成员,数组元素,跨域变量保存在局部变量中来改变JavaScript性能,因为局部变量访问速度越快。
DOM编程

减少DOM编程带来的性能损失

  • 最小化DOM访问次数,尽可能在JavaScript端处理
  • 如果需要多次访问某个DOM节点,请使用局部变量存储它的引用
  • 小心处理HTML集合,因为它实时连系着底层文档,把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,建议把它拷贝到一个数组中。
  • 如果可能的话,可以使用更快的API,如querySelectorALL()和firstElementChild()
  • 要留意重绘和重排,批量修改样式时,“离线”操作DOM树,使用缓存,并减少访问布局信息的次数
  • 动画中使用绝对定位,使用拖放处理
  • 使用事件委托来减少事件处理器的数量
算法和流程控制

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

  • for、While、do-while循环性能特性相当、并没有一种循环类型明显快于或慢于其他类型
  • 避免使用for-in循环,除非你需要你个属性数量未知的对象
  • 改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代次数
  • 通常来说,switch总是比if-else快,但并不总是最佳解决方案
  • 在判断条件较多时,使用查找表比If-else和switch更快
  • 在判断条件较多时,使用查找表比if-else快
  • 浏览器的调用栈大小限制了递归算法在JavaScript中的应用,栈溢出错误会导致其他代码中断运行
  • 如果遇到栈溢出错误,可将方法改为迭代算法,或使用Memoization来避免重复计算
字符串和正则表达式

密集的字符串操作和草率地编写正则表达式可能产生严重的性能障碍

  • 当连接数量巨大或尺寸巨大的字符串时,数组项合并是唯一在IE7及更早版本中性能合理的方法
  • 如果不需要考虑IE7及更早版本的性能,数组项合并是最慢的字符串连接方法之一。推荐使用简单的+和+=操作符替代。避免不必要的中间字符串
  • 回溯即是正则表达式匹配功能的基本组成部分,也是正则表达式的低效之源
  • 回溯失控发生在正则表达式本应快速匹配的地方,但因为某些特殊的字符串匹配动作导致运行缓慢甚至浏览器崩溃。避免这个问题的办法是:使相邻的子元互斥,避免嵌套量词对同一字符串的相同部分多次匹配,通过重复利用预查的原子组去除不必要的回溯
  • 提高正则表达式效率的各种技术手段会有助于正则表达式更快地匹配,并在非匹配位置上花更少的时间
  • 正则表达式并不总是完成的最佳工具,尤其当你只搜索字面字符串的时候
  • 尽管有许多方法可以去除字符串的首位空白,但使用两个简单的正则表达式来处理大量字符串内容能提供一个简单而跨浏览器的方法,从字符串末尾开始循环向前搜索第一个非空白字符,或者将此技术同正则表达式结合起来。会提供一个更好的替代方案。它很少受到字符串长度影响。
快速响应的用户界面

JavaScript和用户界面更新在同一个进程中运行,因此一次只能处理一件事情。这意味着当JavaScript 代码正在运行时,用户界面不能响应输入,反之亦然。高效的管理UI线程就是要确保JavaScript不能运行太长时间,以免印象用户体验。

  • 任何JavaScript任务都不应当执行超过100毫秒。过长的运行时间会导致UI更新出明显的延迟,从而对用户体验产生负面影响。
  • JavaScript运行期间,浏览器响应用户交互的行为存在差异。无论如何,JavaScript长时间运行将导致用户体验变得混乱和脱节。
  • 定时器可用来安排代码延迟执行,它使得你可以长时间运行脚本分解成一系列的小任务。
  • Web workers是新本浏览器支持的特性,它允许你在UI线程外部执行JavaScript代码。从而避免锁定UI。
Ajax

高性能的Ajax包括以下方面:了解你项目的具体需求,选择正确的数据格式与之匹配的传输技术
作为数据格式,纯文本和HTML只适用于特定场合,但他们可以节省客户端的CPU周期。XML被广泛应用且支持良好,但是它十分笨重且解析缓慢。json是轻量级的,解析速度快(被视为原生代码而不是字符串),通用性与XML相当/字符分隔的自定义格式十分轻量,在解析大量数据急时非常快,但需要编写额外的服务端构造程序,并在客户端解析。
当从页面当前所处的域下请求数据时,XHR提供了最完善的控制和灵活性,尽管他会把接收到的所有数据当成一个字符串,且这有可能降低解析速度。;另一方面,动态脚本注入允许跨域请求和本地执行JavaScript和JSON但是它的接口不那么安全,而且还不能读取头信息或响应代码。multipart XHR可以用来减少请求数,并处理一个响应中的各种文件类型,但是他不能缓存接收到的响应。当需要发送数据时,图片信标是一种简单而有效的方法,XHR还可以用POST方法发送大量数据。
加速你的Ajax

  • 减少请求数,可通过合并JavaScript和CSS文件,或使用MXHR。
  • 缩短页面的加载时间,页面主要内容加载完成后,用Ajax获取那些次要的文件。
  • 确保你的代码错误不好输出给用户,并在服务端处理错误
  • 知道何时使用成熟的Ajax类库,以及何时编写自己的底层Ajax代码。
编程实践

为了编写更高效的代码,需注意以下编程实践

  • 通过避免使用eval()和Function()构造器来避免双重求值带来的性能消耗。同样的,给setTimout()和SetInterval()而不是字符串作为参数。
  • 尽量使用直接量创建对象和数组,直接量的创建和初始化都比非直接量形式快。
  • 避免做重复工作。当需要检测浏览器时,可使用延迟加载或条件预加载,
  • 在进行数学计算时,考虑使用直接操作数字的二进制形式的位运算
  • JavaScript的原生方法总会比你写的任何代码都要快,尽量使用原生方法。