面对这些问题最开始(天真)的做法是使用对象存储数据并放入数组中,使用jQuery遍历数据绘制表格并append到DOM中,最后使用事件绑定我们期望地点击行为。
注意:这不是你应该做的
var moduleA = function () { return { data: dataArrayObject, init: function () { this.addTable(); this.addEvents(); }, addTable: function () { for (var i = 0; i < rows; i++) { $tr = $('<tr></tr>'); for (var j = 0; j < this.data.length; j++) { $tr.append('<td>' + this.data[j]['id'] + '</td>'); } $tr.appendTo($tbody); } }, addEvents: function () { $('table td').on('click', function () { $(this).toggleClass('active'); }); } }; }();这段代码简单有效地完成了任务。
但在这种情况下,我们遍历的数据只是本应该简单地存放在数组中的数字型属性ID。有趣的是,直接使用DocumentFragment和本地DOM方法比使用jQuery(以这种方式)来生成表格是更优的选择,当然,事件代理比单独绑定每个td具有更高的性能。
要注意虽然jQuery在内部使用DocumentFragment,但是在我们的例子中,代码在循环内调用append并且这些调用涉及到一些其他的小知识,因此在这里起到的优化作用不大。希望这不会是一个痛点,但请务必进行基准测试,以确保自己代码ok。
对于我们的例子,上述的做法带来了(期望的)性能提升。事件代理对简单的绑定是一种改进,可选的DocumentFragment也起到了助推作用。
var moduleD = function () { return { data: dataArray, init: function () { this.addTable(); this.addEvents(); }, addTable: function () { var td, tr; var frag = document.createDocumentFragment(); var frag2 = document.createDocumentFragment(); for (var i = 0; i < rows; i++) { tr = document.createElement('tr'); for (var j = 0; j < this.data.length; j++) { td = document.createElement('td'); td.appendChild(document.createTextNode(this.data[j])); frag2.appendChild(td); } tr.appendChild(frag2); frag.appendChild(tr); } tbody.appendChild(frag); }, addEvents: function () { $('table').on('click', 'td', function () { $(this).toggleClass('active'); }); } }; }();接下来看看其他提升性能的方式。你也许曾经在哪读到过使用原型模式比模块模式更优,或听说过使用JS模版框架性能更好。有时的确如此,不过使用它们其实是为了代码更具可读性。对了,还有预编译!让我们看看在实践中表现的如何?
moduleG = function () {}; moduleG.prototype.data = dataArray; moduleG.prototype.init = function () { this.addTable(); this.addEvents(); }; moduleG.prototype.addTable = function () { var template = _.template($('#template').text()); var html = template({'data' : this.data}); $tbody.append(html); }; moduleG.prototype.addEvents = function () { $('table').on('click', 'td', function () { $(this).toggleClass('active'); }); }; var modG = new moduleG();事实证明,在这种情况下的带来的性能提升可以忽略不计。模板和原型的选择并没有真正提供更多的东西。也就是说,性能并不是开发者使用它们的原因,给代码带来的可读性、继承模型和可维护性才是真正的原因。
更复杂的问题包括高效地在canvas上绘制图片和操作带或不带类型数组的像素数据。
在将一些方法用在你自己的应用之前,一定要多了解这些方案的基准测试。也许有人还记得JS模版的shoot-off和。你要搞清楚基准测试不是存在于你看不到的那些虚拟应用,而是应该在你的实际代码中去测试带来的优化。
V8优化技巧详细介绍了每个V8引擎的优化点在本文讨论范围之外,当然这里也有许多值得一提的技巧。记住这些技巧你就能减少那些性能低下的代码了。