JavaScript加载
- 将所有
<script>
标签尽可能放置在页面的底部,紧靠 body 关闭标签</body>
的上方,保证页面在脚本 运行之前完成解析样式 - 将脚本成组打包 / 压缩。页面的
<script>
标签越少,页面的加载速度就越快,响应也更加迅速。(单个文件文件也不宜过大,可利用浏览器并行下载能力, 切割成多个文件) - 非阻塞方式下载 JavaScript:动态创建
<script>
元素;用 XHR 对象下载JavaScript代码,并注入到页面中
数据访问
- 局部变量比域外变量快,因为它位于作用域链的第一个对象中。变量在作用域链中的位置越深,访问所需的时间就越长。全局变量总是最慢的,因为它们总是位于作用域链的最后一环。
- 一个对象的属性或方法在原形链中的位置越深,访问它的速度就越慢,查找属性需要往原型链上遍历搜索,所以尽量使用直接量(简单类型)
DOM 编程
- 最小化 DOM 访问,修改 DOM 元素会造成重绘和重新排版
- 在ECMAScript处理数据,最后一次性调用dom操作
-
innerHTML
和createElement / appendChild
性能比较:在老的浏览器 innerHTML 要快得多,在新的浏览器差距不大,甚至 createElement 表现更好 - 遍历数组比遍历集合(HTML Collection 类数组)快,集合的 length 属性缓存到一个变量中,遍历集合时可先转化成数组副本
- 遍历 children 比 childNodes 更快
- 使用速度更快的 API,诸如 querySelectorAll()和 firstElementChild
• offsetTop, offsetLeft, offsetWidth, offsetHeight
• scrollTop, scrollLeft, scrollWidth, scrollHeight
• clientTop, clientLeft, clientWidth, clientHeight
• getComputedStyle() (currentStyle in IE)(在 IE 中此函数称为 currentStyle)
获取布局信息这些属性和方法,需返回最新的数据,浏览器不得不刷新 渲染队列并重排版。所以 不要在布局信息改变时查询它 - 页面中存在大量元素绑定了事件,使用事件托管
算法和流程控制
-
优化循环工作量的第一步是减少对象成员和数组项查找的次数
-
倒序循环是编程语言中常用的性能优化方法
-
forEach 比传统循环(for、while、do while)要慢,每个数组项要关联额外的函数 调用是造成速度慢的原因
-
尽量减少循环中每次迭代的运算量,并减少循环迭代次数
-
除非你要迭代遍历一个属性未知的对象,否则不要使用 for-in 循环
-
switch 表达式总是比 if-else 更快,但只有当条件体数量很大时才明显更快。两者间的主要性能区别在于:当条件体增加时,if-else 性能负担增加的程度比 switch 更多
-
将最常见的(频率高的)条件体放在 if-else 首位(更快作出选择)
-
将 if-else 组织成一系列嵌套的 if-else 替换 else if 再判断,可以减少条件判断。
-
当条件体的数目为大量离散值时,使用查表法(对象/数组/Map 直接选择)
-
任何可以用递归实现的算法都可以用迭代实现。使用优化的循环替代长时间运行的递归函数可以提高性能, 因为运行一个循环比反复调用一个函数的开销要低。
-
减少工作量就是最好的性能优化技术。代码所做的事情越少,它的运行速度就越快
-
使用 memoization 技术,通过缓存先前计算结果为后续计算所重复使用,节省计算时间。
-
算法本身复杂度优化
响应接口
-
字符串合并:大多数情况下 String.prototype.concat 比简单的 + 和 += 慢
-
JavaScript 和UI界面在同一个主线程内运行,同一时刻只能其中一个可以运行。这意味着当 JavaScript 代码正在运行时,用户界面不能响应,反之亦然。
-
JavaScript 运行时间不应该超过 100 毫秒。过长的运行时间导致 UI 更新出现可察觉的延迟,从而对整体用户体验产生负面影响。这时可用定时器让出时间片,分解长运行脚本成为较短的片断
/**
* 用定时器让出时间片, 每25ms后再将任务继续加入执行队列
* 并且做了限时运行代码,在50ms内直接继续下一次的执行,(执行超过50ms后再让出时间片)
* @param {array} items 需要处理的数组对象
* @param {function} process 处理函数
* @param {fucntion} callback 完成回调函数
*/
function timedProcessArray(items, process, callback) {
var todo = items.concat(); //create a clone of the original
setTimeout(function() {
var start = +new Date();
do {
process(todo.shift());
} while (todo.length > 0 && (+new Date() - start < 50));
if (todo.length > 0) {
setTimeout(arguments.callee, 25);
} else {
callback(items);
}
}, 25);
}
- 通过使用Web Workers,Worker 可以在独立于主线程(通常是UI线程)的后台线程中,执行费时的处理任务。主线程不会因此被阻塞/放慢。
- 数据格式 越轻量级越好,最好是 JSON 和字符分隔的自定义格式。xml、json、html、custom各数据格式下载和解析的性能测试
编程实践
- eval,Function构造器,setTimeout 和 setInterval 允许在程序中运行包含代码的字符串,执行过程中会发生二次评估(二次评估是一项昂贵的操作),且可能是不安全的。所以,避免使用 eval 和 Function 构造器避免二次评估;给 setTimeout() 和 setInterval() 传递函数参数而不是字符串参数
- 创建对象或数组使用直接量最快,占用较少空间
- 不要做不必要的工作,不要重复做已经完成的工作
- 延迟加载、条件预加载
- 使用速度快的部分
- 尽量使用原生方法
构建与部署
- 预处理JavaScript文件:
- 合并 JavaScript 文件,减少 HTTP 请求的数量
- JavaScript Minification(紧凑): 剔除 js 文件中一切运行无关的内容,包括注释和不必要的空格
- JavaScript Compression(压缩):携带 Accept-Encoding 的 HTTP 头(gzip 编码)
- Caching JavaScript Files:使用 http缓存,通过向文件名附加时间戳或版本号解决缓存问题;使用 HTML 5 离线应用程序缓存
- 使用内容传递网络(CDN)提供 JavaScript 文件,CDN 不仅可以提高性能,它还可以为你管理压缩和缓 存
网友评论