第一章 加载和运行
管理浏览器中的 javaScript 代码是个棘手的问题,代码的执行会阻塞其他浏览器的处理过程。每当遇到 script 标签,必须停下来等待代码下载再执行其他部分。同时浏览器再遇到 < body> 标签之前不会渲染页面的任何部分。
几种减少 JS 对性能影响的方法
- 将所有< script> 标签放在页面的底部,紧靠 body 关闭标签的上方。可以保证页面在脚本运行之前完成解析;
- 将脚本分组打包。页面的< script> 标签越少,页面的加载速度越快,响应也越快。不论外部还是内联代码都是如此。
- 可以使用非阻塞方法下载JavaScript
- 为< script> 标签 添加 defer 属性(只适用于 IE 和 firefox 3.5以上的版本);
- 动态创建 script 元素,用它下载并执行代码
- 用 XHR 对象下载代码,并注入到页面中。
第二章 数据访问
数据应当存放在什么地方,以实现最佳的读写效率?数据存储位置可以对代码整体性能产生重要影响
有四种数据访问类型:直接量、变量、数据项、对象成员
- 直接量 和 局部变量 的访问速度非常快,数据项和对象成员需要更长的时间
- 局部变量比域外变量快,因为它位于作用域链中的第一个对象中,变量在作用域链中的位置越深访问所需时间越长。(全局变量总是最慢的,它位于作用域链的最后一环)
- 避免使用 with(改变了运行期上下文的作用域连)和 try-catch
- 少用嵌套对象
- 一个属性在原型链中的位置越深,访问所需要的时间越长。同时搜索比读取更费时间
- 提高 JS 代码性能的方式有:将经常使用的对象成员、数组项、域外变量存储到局部变量中。
第三章 DOM 编程
对于 DOM 操作,在富网应用中通常是一个性能瓶颈。本章讨论三个问题
- 访问和修改 DOM 元素
- 修改 DOM 元素的样式,造成重绘和重排版
- 通过 DOM 事件处理用户响应。
文档对象模型(DOM)是一个独立于语言的,使用XML和HTML文档操作的应用程序接口(API)。DOM Apis 主要用于访问这些文档中的数据流。在浏览器中接口是以 JavaScript 实现的。客户端大多数脚本程序与文档打交道。
为了减少 DOM 编程中的性能损失,可记住以下几点:
- 最小化 DOM 访问,在 JavaScript 端做尽可能多的事情;
- 在反复访问的地方使用局部变量存储 DOM 引用;
- 小心处理 HTML 集合,会总是对底层文档进行重新查询。可以将集合的 length 缓存到变量中,在迭代中访问这个变量。如果经常操作这个集合,可以将集合拷贝到数组中;
- 使用速度更快的 API,例如 querySelectAll() 、firstElementChild;
- 注意重绘和重排版;批量修改风格,离线操作 DOM 树;缓存并减少对布局信息的访问;
- 动画中使用绝对坐标,使用拖放代理;
- 使用事件托管技术最小化事件句柄数量;
算法和流程控制
代码整体结构是执行速度的决定因素之一。性能损失与代码组织方式和具体问题解决办法直接相关。
与其他编程语言不通的是,JavaScript 可用的资源有限,所以优化技术至关重要。
- for、while、do-while 的循环性能特性相似,谁也不比谁快或者慢;
- 除非你需要遍历一个属性未知的对象,否则不要使用 for-in 循环;
- 改善循环的方法就是改善每次迭代中的运算量,同时减少迭代次数;
- 一般来说,switch 总是比 if-else 更快;
- 当判断条件更多的时候,查表法比 if-else 或者 switch 更快;
- 浏览器的调用栈尺寸限制了递归算法在JavaScript中的应用;栈溢出错误导致其他代码也不能正常执行;
- 如果遇到了一个栈溢出的错误,将方法修改为一个迭代算法或者使用制表法可用避免重复工作;
可以发现,当运行的代码量越大,使用这些策略带来的性能提升就越明显。
第五章 字符串和正则表达式
几乎所有的 JavaScript 程序都与字符串操作紧密相连。
密集的字符串操作和粗浅的编写正则表达式都可能是主要性能障碍。关于性能优化建议如下:
- 当连接数量巨大或尺寸巨大的字符串时,数组联合是 IE7 话他的早期版本上唯一具有合理性的方法;
- 如果你不关心 IE7 和他的早期版本,数组联合是连接字符串最慢的方法之一。使用简单的 + 和 += 取而代之,可以避免(产生)不必要的中间字符串。
- 回溯既是正则表达式匹配功能基本的组成成分,又是正则表达式影响效率的常见原因。
- 回溯时空发生在正则表达式本应该很快发现匹配的地方。因为某些特殊的匹配字符串动作,导致运行缓慢甚至浏览器崩溃。避免此类问题的技术包括:使用领字元互斥,避免嵌套词量对一个字符串的相同部分多次匹配,通过重复利用前瞻操作的原子特性去除步不要的回溯;
- 提高正则表达式效率的各种手段
- 正则表达式并不总是完成工作的最佳工具,特别是当你只是搜索一个文本字符串时
- 虽然有很多方法来修饰一个字符串,使用两个简单的正则表达式提供了一个简介、跨浏览器的方法,适用于不同内容和长度的字符串。
第六章 响应接口
网页应用程序的响应速度也是影响用户性能体验的关键。JavaScript 和用户界面更新在同一个进程内运行,同一时刻只有其中一个可以运行。 JavaScript 和UI 更新共享的进程通常被称为浏览器 UI 线程。
- 浏览器在 JS 运行时间上采取了 现实。 一个是调用栈尺寸,一个是长时间脚本限制。 JavaScript 可连续运行的最大时间是1000毫秒。
任何超过 100 毫秒的处理,都应该考虑 web Worker 方案是不是比基于定时器的方案更合适,当然还要考虑浏览器是否支持 web Worker 。 web Worker 适合于纯数据的,或者浏览器与 UI 没关系的长运行脚本。用其解析一个大字符串只是许多好处之一。其还可能受益的任务如下:
- 编/解码一个大字符串;
- 复杂数学运算(包括图像或者视频)
- 给一个大数组排序
第七章 Ajax - 异步 JavaScript 和 HTML
ajax 是高性能 JavaScript 的基石。它可以通过延迟下载大量资源使页面加快。通过在客户端和服务器之前异步传递数据,避免页面集体加载。还用于在一次 HTTP 请求中获取整个页面的资源。
作为数据格式,纯文本和 HTML 是高度限制的,但是他们可以节省客户端的 CPU 周期。
当从页面跨域请求数据时,XHR 提供最完善的控制和灵活性。动态脚本标签插入技术允许跨域请求和本地运行 JS,但是他的接口不够安全,且不能读取信息头或响应报文代码。多部分的 XHR 可以减少请求数量,可以响应不同的文件类型,不能缓存收到的响应报文。
当发送数据的时候,图像灯标是最简单和有效的方法。XHR 也可以用 POST 发送大量数据。
除了这些格式和传输技术之外,还有一些可以提高 Ajax 的速度:
- 减少请求数量,可以通过 JS 和 CSS 文件打包,或者使用 MXHR;
- 缩短页面的加载时间,在页面其他内容加载之后,使用 Ajax 获取少量重要的文件;
- 确保代码错误不要直接显示给用户,并在服务器端做错误处理;
- 学会何时使用健壮的 Ajax,何时自己编写一个底层 Ajax 代码。
第八章 编程实践
- 避免二次评估是实现最优化的 JavaScript 运行时性能的关键。 大多数情况下,没必要使用eval_r() 或 Function(). setTimeout 和 setInterval ,建议第一个参数传入一个函数。
- 使用对象/数组直接量。直接量赋值很快;
- 不要重复工作;
- 延迟加载。调用一个延迟加载函数总是在第一次使用较长的时间,后续调用会快很多;
- 条件预加载。在脚本加载之前提前进行检查,而不用等待函数调用;
- 位操作运算符。可以使用为运算符、掩码替代纯数学操作,
- 原生方法总是比 JS 要快一些。
第九章 创建并部署高性能的 JS 应用
- 合并 JS 文件,减少 HTTP 请求数量
- 以压缩形式提供 JS 文件
- 通过设置 HTTP 响应报头使得 JS 文件可以缓存,通过向文件附加时间戳解决缓存问题;
- 使用内容分发(CDN)提供 JS 文件,可以提高性能,还能管理压缩和缓存;
第十章 工具
当确定脚本加载和运行时的瓶颈所在时,合手的工具是必不可少的。
- 性能分析
- 网络分析