↗☻【高性能网站建设进阶指南 #BOOK#】第7章 编写高效的JavaScript
理解JavaScript中如何管理作用域和作用域链很重要,因为在作用域中要查找的对象个数直接影响标识符解析的性能。标识符在作用域链中的位置越深,查找和访问它所需时间就越长;如果作用域管理不当,就会给脚本的执行时间带来负面影响
到目前为止,局部变量是JavaScript中读写最快的标识符。因为它们存在于执行函数的活动对象中,解析标识符只需要查找作用域链中的单个对象。读取变量值的总耗时随着查找作用域链的逐层深入而不断增长,所以标识符越深存取速度越慢。这种现象几乎在所有浏览器上都存在,只有基于V8 JavaScript引擎的Google Chrome和基于Nitro JavaScript引擎的Safari 4+例外,它们的存取速度超快,标识符深度的影响微乎其微了
任何非局部变量在函数中的使用超过一次时,都应该将其存储为局部变量
在数据存取时,将函数中使用超过一次的对象属性或数组元素存储为局部变量是一种好方法
var doc = document;
var count = data.count;
当value为9时,执行完成的时间会比value为0时要长,因为它之前的所有条件都需要判断
将条件按频率降序排列
将条件拆分成几个分支
在仅判断一两个条件时,if语句通常比switch语句更快。当有两个以上条件且条件比较简单时,switch语句往往更快。这是因为大多数情况下,switch语句中执行单个条件所需时间比在if语句中短,所以当有大量的条件判断时,使用switch语句更合适
使用if语句的情况:
两个之内的离散值需要判断
大量的值能容易地分到不同的区间范围中
使用switch语句的情况
超过两个而少于10个离散值要判断
条件值是非线性,无法分离出区间范围
使用数组查询的情况
超过10个值需要判断
条件对应的结果是单一值,而不是一系列操作
展开循环,处理大数组
最常见的脚步执行时间过长的原因包括
过多的DOM交互
过多的循环
过多的递归
定时器是在浏览器中拆分执行JavaScript代码的惯用方式。每当脚本需要花太长时间来完成的时候,就让部分延迟执行
注意过小的延迟也会引起浏览器不响应。不建议使用0毫秒的延迟,因为所有的浏览器都无法再这么短的时间里正确地更新页面显示。一般而言,延迟50~100毫秒是合适的,这足够让浏览器有时间执行必要的页面刷新
<!doctype html> <html lang="zh-CN"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <script> var result = (function() { switch (6) { case 0: return 'result0'; case 1: return 'result1'; case 2: return 'result2'; case 3: return 'result3'; case 4: return 'result4'; case 5: return 'result5'; case 6: return 'result6'; case 7: return 'result7'; case 8: return 'result8'; case 9: return 'result9'; case 10: return 'result10'; } })(); console.log(result); var results = ['result0', 'result1', 'result2', 'result3', 'result4', 'result5', 'result6', 'result7', 'result8', 'result9', 'result10']; result = results[9]; console.log(result); var length = results.length; var html = ''; for (var i = length; i--;) { html = results[i] + html; } console.log(html); function process(value) { console.log(value); } for (var i = length; i--;) { process(results[length - 1 - i]); } // 展开循环 var iterations = Math.ceil(length / 8); var startAt = length % 8; var i = 0; do { switch (startAt) { case 0: process(results[i++]); case 7: process(results[i++]); case 6: process(results[i++]); case 5: process(results[i++]); case 4: process(results[i++]); case 3: process(results[i++]); case 2: process(results[i++]); case 1: process(results[i++]); } startAt = 0; } while (--iterations > 0); var buffer = [], i = 0; buffer[i++] = 'Hello'; buffer[i++] = ' '; buffer[i++] = 'World!'; console.log(buffer.join('')) function trim(text) { return text.replace(/^\s+|\s+$/g, ''); } function trim(text) { return text.replace(/^\s+/, '').replace(/\s+$/, ''); } function trim(text) { text = text.replace(/^\s+/, ''); for (var i = text.length -1; i >=0; i--) { if (/\S/.test(text.charAt(i))) { text = text.substring(0, i + 1); break; } } return text; } window.onload = function() { setTimeout(function() { console.log(buffer.join('')) setTimeout(function() { console.log(buffer.join('')) }, 100); console.log(buffer.join('')) }, 100); }; function chunk(array, process, context) { setTimeout(function() { var item = array.shift(); process.call(context, item); if (array.length > 0) { setTimeout(arguments.callee, 100); } }, 100); } var names = ['Nicholas', 'Steve', 'Doug', 'Bill', 'Ben', 'Dion'], todo = names.concat(); chunk(todo, function(item) { console.log(item); }); function sort(array, onComplete) { var pos = 0; (function() { var j, value; for (j = array.length; j > pos; j--) { if (array[j] < array[j - 1]) { value = array[j]; array[j] = array[j - 1]; array[j - 1] = value; } } pos++; if (pos < array.length) { setTimeout(arguments.callee, 100); } else { onComplete(); console.log(array); } })(); } sort([2,1,5,3,9,7], function() { console.log('Done!'); }); </script> </body> </html>