Эффективная замена строк в блоке HTML в Javascript - PullRequest
0 голосов
/ 13 февраля 2012

Я использую Javascript (с Mootools) для динамического построения большой страницы с использованием HTML-элементов «template», многократно копируя один и тот же шаблон для заполнения страницы. В каждом шаблоне я использую строковые ключевые слова, которые необходимо заменить, чтобы создать уникальные идентификаторы. У меня есть серьезные проблемы с производительностью, однако в том, что для выполнения всех этих замен требуется несколько секунд, особенно в IE. Код выглядит так:

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 ...). Все остальное работает нормально, он заменяет только эти идентификаторы, что, похоже, является узким местом производительности. Кто-нибудь знает, есть ли способ сделать это эффективно, или причина, по которой он может работать так медленно? Элементы начинают скрываться и не захватываются DOM до тех пор, пока они не будут созданы, поэтому перерисовки не происходит.

Кстати, причина, по которой я строю страницу таким образом, состоит в том, чтобы поддерживать чистоту кода, так как мы должны иметь возможность динамически создавать новые элементы и после загрузки. Выполнение этого на стороне сервера усложнит ситуацию.

Ответы [ 2 ]

2 голосов
/ 13 февраля 2012

Я не уверен на 100%, но мне кажется, что проблема в индексации дерева dom.

Прежде всего, вы должны использовать идентификаторы или вы можете управлять классами?поскольку вы говорите, что замена идентификатора является основной проблемой.

Кроме того, почему вы клонируете часть дерева 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);

Я думаю, что это может улучшить эффективность, так как он не клонируется, а затем снова его проиндексировать, но я не уверен.попробуйте и посмотрите, что произойдет.

1 голос
/ 14 февраля 2012

есть некоторые вещи, которые вы можете сделать, чтобы оптимизировать его - и то, что сказал @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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...