我正在使用Javascript(与Mootools)来使用HTML“模板”元素动态构建大页面,多次复制同一模板以填充页面。在每个模板中,我使用需要替换的字符串关键字来创建唯一的ID。但是,我遇到了严重的性能问题,因为执行所有这些替换都需要花费几秒钟的时间,尤其是在IE中。代码如下:
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
fieldTr.removeClass('fieldTemplate');
replaceIdsHelper(fieldTr, ':FIELD_NODE_ID:', fieldNodeId);
parentTable.grab(fieldTr);
根据IE9的分析器,replaceIdsHelper()是问题方法。我尝试了此方法的两种实现:
// Retrieve the entire HTML body of the element, replace the string and set the HTML back.
var html = rootElem.get('html').replace(new RegExp(replaceStr, 'g'), id);
rootElem.set('html', html);
和
// Load the child elements and replace just their IDs selectively
rootElem.getElements('*').each(function(elem) {
var elemId = elem.get('id');
if (elemId != null) elemId = elemId.replace(replaceStr, id);
elem.set('id', elemId)
});
但是,考虑到调用此方法的次数(大约200 ...),这两种方法都非常慢。其他一切运行正常,只是替换了这些ID,这似乎是主要的性能瓶颈。有谁知道是否有一种方法可以有效地执行此操作,或者原因可能是运行如此缓慢?元素开始隐藏,直到创建后才被DOM抓取,因此不会发生重绘。
顺便说一下,我以这种方式构建页面的原因是保持代码干净,因为我们还需要能够在加载后动态创建新元素。从服务器端执行此操作会使事情复杂得多。
最佳答案
您可以做一些事情来优化它-@nizan tomer所说的非常好,伪模板是一个很好的模式。
首先。
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
您应该这样做:
var templateHTML = somenode.getElement(".fieldTemplate").get("html"); // no need to clone it.
模板本身应该/可以像建议的那样,例如:
<td id="{id}">{something}</td>
只读取一次,无需为每个项目都克隆它-而是使用新的Element构造函数并只设置innerHTML-注意它缺少
<tr> </tr>
。如果您有一个带有数据的对象,例如:
var rows = [{
id: "row1",
something: "hello"
}, {
id: "row2",
something: "there"
}];
Array.each(function(obj, index) {
var newel = new Element("tr", {
html: templateHTML.substitute(obj)
});
// defer the inject so it's non-blocking of the UI thread:
newel.inject.delay(10, newel, parentTable);
// if you need to know when done, use a counter + index
// in a function and fire a ready.
});
或者,使用文档片段:
Element.implement({
docFragment: function(){
return document.createDocumentFragment();
}
});
(function() {
var fragment = Element.docFragment();
Array.each(function(obj) {
fragment.appendChild(new Element("tr", {
html: templateHTML.substitute(obj)
}));
});
// inject all in one go, single dom access
parentTable.appendChild(fragment);
})();
我对这两种方法都进行了jsperf测试:
http://jsperf.com/inject-vs-fragment-in-mootools
chrome以惊人的优势与Firefox和ie9取得了令人惊讶的胜利。同样令人惊讶的是,在Firefox中,单个注入比片段更快。瓶颈可能是表格中的TR,这一直很不可靠。
对于模板:您还可以查看使用诸如mustache或underscore.js模板之类的东西。