2012-02-13 39 views
0

我正在使用Javascript(與Mootools)使用HTML「模板」元素動態構建大頁面,複製相同模板多次以填充頁面。在每個模板中,我使用需要替換的字符串關鍵字來創建唯一的ID。但是,我遇到了嚴重的性能問題,因爲它需要幾秒鐘來執行所有這些替換,特別是在IE中。代碼如下所示:有效替換Javascript中的HTML塊中的字符串

var fieldTemplate = $$('.fieldTemplate')[0]; 
var fieldTr = fieldTemplate.clone(true, true); 
fieldTr.removeClass('fieldTemplate'); 
replaceIdsHelper(fieldTr, ':FIELD_NODE_ID:', fieldNodeId); 
parentTable.grab(fieldTr); 

replaceIdsHelper()是根據IE9的分析器的問題方法。我試過這個方法的兩種實現方式:

// 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抓取,直到它們被創建之後纔會發生重繪。

順便說一下,我這樣構建頁面的原因是爲了保持代碼乾淨,因爲我們需要能夠在加載後動態地創建新元素。從服務器端執行此操作會使事情變得更加複雜。

回答

1

有一些事情可以優化它 - 而且@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

由鉻巨大的利潤與Firefox和ie9的勝利。同樣令人驚訝的是,在Firefox中,個人入侵比碎片更快。也許瓶頸在於它是一張桌子上的TR,而這一直是狡猾的。

對於模板:你也可以看看使用類似mustache或underscore.js模板的東西。

+0

謝謝,這是很多很好的建議。我絕對可以通過這種方式加快速度。 我認爲我在JS中構建整個頁面的方法過於客戶端密集型,但我們必須支持IE7,用戶也可能會使計算機速度變慢......所以我要做的是通過製作很少有JSP標籤用起始數據填充頁面,然後使用這些相同的標籤創建我可以爲新條目複製的模板。 – 2012-02-16 22:59:02

2

我不是100%確定,但它聽起來是問題是與dom樹的索引。

首先,您是否必須使用ID或可以使用類來管理?因爲你說替換id是主要問題。

另外,你爲什麼要克隆部分dom樹而不是插入一個新的html? 您可以用String(用MooTools的時候)的替代方法,例如:

var template = '<div id="{ID}" class="{CLASSES}">{CONTENT}</div>'; 
template.substitute({ID: "id1", CLASSES: "c1 c2", CONTENT: "this is the content" }); 

你可以閱讀更多關於它在這裏http://mootools.net/docs/core/Types/String#String:substitute

然後,只是把這個字符串,並把它作爲HTML裏面容器,讓我們說:

$("container_id").set("html", template); 

我認爲,它可能會提高效率,因爲它不會複製,然後再建立索引,但我不能肯定。給它一個去看看會發生什麼。