Javascript эффективно создает таблицу из JSON и добавляет ее в DOM

у меня есть JSON-массив с сервера с массивом 200 объектов, каждый из которых содержит еще 10 объектов, которые я хочу отобразить в виде таблицы. Сначала я создавал <tr> для каждой итерации и использования jQuery для добавления <td> построен из значений массива в <tr>. Это заняло около 30 секунд в Chrome и 19 секунд в IE 8. Это заняло слишком много времени, поэтому я попытался переключиться на Array.join() метод, где я буду хранить каждую строку, которая будет вся таблица в массиве, и в конце do $('#myTable').append(textToAppend). Это на самом деле хуже, чем моя первая версия примерно на 5 секунд.

Я хотел бы получить это около 10 секунд. Есть ли у меня шанс? Если нет, я просто буду добавлять по одной строке за раз, но я бы предпочел этого не делать.

for(allIndex = 0; allIndex < entries.alumnus.length; allIndex++){

  var entry = '<tr id="entry' + allIndex + '" class="entry"></tr>';
  $('#content_table').append(entry);

  $('#entry' + allIndex).append(($.trim(entries.alumnus[allIndex].title) != '' ?
        '<td id="title' + allIndex + '" class="cell"><span class="content">' +
         entries.alumnus[allIndex].title + '</span></td>' : '<td width="5%">' + 
         filler + '</td>'));    
  .
  .
  .
  .//REST OF ELEMENTS
  .
  .
  .
}   

обновление: я, должно быть, что-то перепутал вчера, потому что я вернулся к попытке добавления элементов из DOM, а затем присоединил их позже, без используя jQuery, и я получил свое время до 85 ms В Chrome и 450 ms в IE7!!! Вы, ребята, потрясающие!!! Я дал user1 ответ, потому что он был более всеобъемлющим, и использование фрагментов не сильно изменило мое время в Chrome и добавило около 20 мс в IE7. Но я все еще ценю ответ @Emre Erkan и буду использовать чаще:)

5 ответов


самый быстрый будет выглядеть так:

var oldTable = document.getElementById('example'),
    newTable = oldTable.cloneNode(true);
for(var i = 0; i < json_example.length; i++){
    var tr = document.createElement('tr');
    for(var j = 0; j < json_example[i].length; j++){
        var td = document.createElement('td');
        td.appendChild(document.createTextNode(json_example[i][j]));
        tr.appendChild(td);
    }
    newTable.appendChild(tr);
}

oldTable.parentNode.replaceChild(newTable, oldTable);

и должен работать в миллисекундах. Вот пример:http://jsfiddle.net/Paulpro/YhQEC/ он создает 200 строк таблицы, каждая из которых содержит 10 td.

вы хотите добавить с помощью элементов, а не строк, но вы не хотите ничего добавлять к DOM, пока не закончите создание всей структуры (чтобы избежать оплавления в цикле). Таким образом, вы можете клонировать исходную таблицу и добавить к клону, а затем вставьте клон после завершения цикла.

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

ваш код может выглядеть так:

var oldTable = document.getElementById('content_table'),
    newTable = oldTable.cloneNode(true),
    tr, td;
for(var i = 0; i < entries.alumnus.length.length; i++){
    tr = document.createElement('tr');
    tr.id = 'entry' + i;
    tr.className = 'entry';

    if(entries.alumnus[i].title){
        td = document.createElement('td');
        td.id = 'title' + i;
        td.className = 'cell';
        var span = document.createElement('span');
        span.className = 'content';
        span.appendChild(document.createTextNode(entries.alumnus[i].title);
        td.appendChild(span);
        tr.appendChild(td);
        tr.appendChild(createFiller(filler));
    }

    // REST OF ELEMENTS

    newTable.appendChild(tr);

}

oldTable.parentNode.replaceChild(newTable, oldTable);

function createFiller(filler){
    var td = document.createElement('td');
    td.style.width = '5%';
    td.appendChild(document.createTextNode(filler);
    return td;
}

Я предлагаю вам использовать DocumentFragment и использовать собственный javascript для такого рода массовых манипуляций DOM. Я подготовил пример, вы можете проверить его здесь.

var fragment = document.createDocumentFragment(),
    tr, td, i, il, key;
for(i=0,il=data.length;i<il;i++) {
    tr = document.createElement('tr');
    for(key in data[i]) {
        td = document.createElement('td');
        td.appendChild( document.createTextNode( data[i][key] ) );
        tr.appendChild( td );
    }
    fragment.appendChild( tr );
}
$('#mytable tbody').append( fragment );

Я думаю, что это самый быстрый способ сделать такую работу.


самое главное-создать все содержимое таблицы из DOM, а затем вставить в таблицу. Этот в chrome заканчивается примерно через 3 до 5 мс:

function createTableFromData(data) {
    var tableHtml = '';
    var currentRowHtml;
    for (var i = 0, length = data.length; i < length; i++) {
        currentRowHtml = '<tr><td>' + data[i].join('</td><td>') + '</td></tr>';
        tableHtml += currentRowHtml;        
    }  
    return tableHtml;    
}

var textToAppend= createTableFromData(yourData);
$('#myTable').append(textToAppend);

Если у вас есть строка проверки JSON с сервера, и структура надежно представляет собой массив массивов строк, приведенное ниже позволит вам избежать синтаксического анализа JSON и вместо этого заменить генерацию HTML постоянной серией операций регулярного выражения, которые, как правило, реализуются в собственном коде, использующем собственные буферы. Это должно полностью избежать одного синтаксического анализа и заменить любые буферные копии, которые стоят O(n**2) на K, O (n) буферные копии для константы k.

var jsonContent
    = ' [ [ "foo", "bar", "[baz\"boo\n]" ], ["1","2" , "3"] ] ';

var repls = {  // Equivalent inside a JSON string.
  ',': "\u002b",
  '[': "\u005b",
  ']': "\u005d"
};
var inStr = false;  // True if the char matched below is in a string.
// Make sure that all '[', ']', and ',' chars in JSON content are
// actual JSON punctuation by re-encoding those that appear in strings.
jsonContent = jsonContent.replace(/[\",\[\]]|\./g, function (m) {
  if (m.length === 1) {
    if (m === '"') {
      inStr = !inStr;
    } else if (inStr) {
      return repls[m];
    }
  }
  return m;
});

// Prevent XSS.
jsonContent = jsonContent.replace(/&/g, "&amp;")
   .replace(/</g, "&lt;");
// Assumes that the JSON generator does not encode '<' as '\u003c'.

// Remove all string delimiters and space outside of strings.
var html = jsonContent
    .replace(/\"\s*([,\]])\s*\"?|\s*([\[,])\s*\"/g, "");
// Introduce the table header and footer.
html = html.replace(/^\s*\[/g, "<table>")
html = html.replace(/]\s*$/g, "</table>")
// Introduce row boundaries.
html = html.replace(/\],?/g, "</tr>")
html = html.replace(/\[/g, "<tr><td>")
// Introduce cell boundaries.
html = html.replace(/,/g, "<td>")

// Decode escape sequences.
var jsEscs = {
  '\n': '\n',
  '\f': '\f',
  '\r': '\r',
  '\t': '\t',
  '\v': '\x0c',
  '\b': '\b'
};
html = html.replace(/\(?:[^u]|u[0-9A-Fa-f]{4})/g, function (m) {
      if (m.length == 2) {
        // Second branch handles '\"' -> '"'
        return jsEscs[m] || m.substring(1);
      }
      return String.fromCharCode(parseInt(m.substring(2), 16));
    });

// Copy and paste with the below to see the literal content and the table.
var pre = document.createElement('pre');
pre.appendChild(document.createTextNode(html));
document.body.appendChild(pre);
var div = document.createElement('div');
div.innerHTML = html;
document.body.appendChild(div);

Это определенно возможно. Я не думаю, что конкатенация строк-это путь. В общем, кажется, что быстрее создавать элементы и манипулировать ими, когда они не прикреплены к основному DOM; поэтому сначала создайте всю таблицу, а затем добавьте ее. В простом javascript я думаю, что код ниже в основном то, что вы хотите достичь..

    //mock up the data (this will come from you AJAX call)..
    var data = [];
    for(var i = 0; i < 200; i++){
        var rowData = [];
        for(var j = 0; j < 10; j++){
            rowData.push("This is a string value");
        }
        data.push(rowData);
    }

    //create table..
    var table = document.createElement("table");
    for(var i = 0; i < data.length; i++){
        var rowData = data[i];
        var row = document.createElement("tr");
        for(var j = 0; j < rowData.length; j++){
            var cell = document.createElement("td");
            cell.innerHTML = rowData[j];
            row.appendChild(cell);
        }
        table.appendChild(row);
    }
    //finally append the whole thing..
    document.body.appendChild(table);

когда я вставляю это в консоль в Safari, он запускается через