javascript 的性能问题
1) 控制作用域
对变量的符号的查询总是沿着作用域链, 从局部作用域开始查询, 如果查到了就停止, 否则继续查询外层作用域 ....一直到全局作用域为止。
所以: 对全局变量的访问时间 > 对局部变量的访问时间。因此要局部变量缓存全局对象可以提高性能。
// Bad example: // 对于全局对象 document的访问, 每次访问document都会进行作用域链查找, 一直查找到全局作用域, 降低了性能. function updateUI_Bad() { var imgs = document.getElementsByTagName("img"); for (var i = 0, len = imgs.length; i < len; i++) { imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innerHTML = "Update complete."; }
// Good example: // 把全局对象document存在本地. 除了第一次, 以后使用doc, 减少了作用域链的访问时间. function udpateUI_Good() { var doc = document; var imgs = doc.getElementsByTagName("img"); for (var i = 0, len = imgs.length; i < len; i++) { imgs[i].title = doc.title + " image " + i; } var msg = doc.getElementById("msg"); msg.innerHTML = "Update complete."; }
2) 避免不必要的属性查找
一旦多次用到的对象属性, 应该将其存储在局部变量中。第一次访问该值复杂度是O(n), 以后访问的复杂度是O(1).
不要console(a.b.c); console(a.b.c); console(a.b.c); console(a.b.c); console(a.b.c);
而要 var c = a.b.c; console(c); console(c); console(c); console(c); console(c);
// 访问变量, 数字的复杂度是 O(1) var value = 5; // O(1) var sum = 10 + value; // O(1)
// 访问数组中的元素的复杂度也是O(1) var values = [5, 10]; // O(1) var sum = values[0] + values[1];// O(1)
// 访问对象上的属性的复杂度是 O(n)
// Bad example: var query = window.location.href.substring(window.location.href.indexOf("?")); // 查找 "substring" (window.location.href.substring) 有3次查找 // 查找 "indexOf" (window.location.href.indexOf) 有3次查找
// Good example: var url = window.location.href; var query = url.substring(url.indexOf("?")); // 只有4次属性查找
3) 避免双重解释
如果代码包含在字符串中, javascript 代码运行的同时必须启动一个新的解析器来解析新的代码(写成字符串形式的代码)。而启动一个新的解析器会产生开销, 影响效率。
// Bad eval("alert(‘Hello world!‘)"); // Good alert(‘Hello world!‘);
// Bad var sayHi = new Function("alert(‘Hello world!‘)"); // Good var sayHi = function() { alert(‘Hello world!‘); };
// Bad setTimeout("alert(‘Hello world!‘)", 5000); // Good setTimeout(function() { alert(‘Hello world!‘); }, 5000)
4) 减少 DOM 更新次数
// Bad example // 添加每个item 需要 2 次 DOM 更新 : 一个添加 <li> 元素, 两一个给 <li> 添加文本节点. // 为 list 添加 10 个元素, 共需要 20 次 DOM 更新. var list = document.getElementById("myList"); for (var i = 0; i < 10; i++) { var item = document.createElement("li"); list.appendChild(item); item.appendChild(document.createTextNode("Item " + i)); }
// Good example // 使用 DocumentFragment, 把 <li> 添加到 DocumentFragment 上, 最后一次性地把 DocumentFragment 更新到 <list> 上 var list = document.getElementById("myList"), fragment = document.createDocumentFragment(); for (var i = 0; i < 10; i++) { var item = document.createElement("li"); item.appendChild(document.createTextNode("Item " + i)); fragment.appendChild(item); } list.appendChild(fragment);
5) innerHTML
innerHTML 速度 > createElement() + appendChild()。
因为 后台会为 innerHTML 创建一个 HTML 解析器, 使用内部的 DOM 调用创建 DOM 结构, 而不是基于 JS 的 DOM 调用。内部方法是编译好的二进制调用而不是解析调用, 所以速度快。
使用 innerHTML 时需要注意最小化对 innerHTML 的调用:
// Bad example for (var i = 0; i < 10) { list.innerHTML += "<li>Item " + i + "</li>"; // 这里每一次运算, 都会产生一次 DOM 操作: // 1) innerHTML += "<li>Item "; 2) innerHTML += i; 3) innerHTML += "</li>"; }
// Good example for (var i = 0; i < 10) { var item = "<li>Item " + i + "</li>"; list.innerHTML += item; }
6) 注意 NodeList
操作返回 NodeList 对象的操作包括: getElementsByTagName(), 获取元素的 childNodes 属性, 获取元素的 attributes 属性, 访问特殊集合: document.form / document.images。
访问 DOCUMENT 的 元素 list 开销很大, 应该尽量减少对 元素 list的访问。
// var imageList = document.getElementsByTagName("img"); // imageList : NodeList // Good example for (var i = 0, len = imageList.length; i < len; i++) { // 使用 len 保存 imageList.length, 而不是每次都访问 imageList.length. var image = imageList[i]; // 使用 image 保持当前的 imageList[i], 而不是每次都访问 imageList[i]. }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。