Javascript эффективно построить таблицу из JSON и добавить ее в DOM - PullRequest
8 голосов
/ 05 января 2012

У меня есть JSON-массив, поступающий с сервера с массивом из 200 объектов, каждый из которых содержит еще 10 объектов, которые я хочу отобразить в табличном формате. Сначала я создавал <tr> для каждой итерации и использовал jQuery для добавления <td>, построенного из значений массива, к <tr>. Это заняло около 30 секунд в Chrome и 19 секунд в IE 8. Это заняло слишком много времени, поэтому я попытался переключиться на метод Array.join(), где я буду хранить каждую строку, которая будет составлять всю таблицу, в массиве, и в конец сделать $('#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 мс в Chrome и 450 мс в IE7 !!! Вы, ребята, потрясающие !!! Я дал user1 ответ, потому что этот был более всеобъемлющим, и использование фрагментов не сильно изменило мое время в Chrome и добавило около 20 мс в IE7. Но я все еще ценю ответ @Emre Erkan и буду использовать чаще :)

Ответы [ 5 ]

13 голосов
/ 05 января 2012

Самый быстрый будет выглядеть примерно так:

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 тд.

Вы хотите добавлять элементы, а не строки, но не хотите добавлять что-либо в 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;
}
9 голосов
/ 05 января 2012

Я предлагаю вам использовать 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 );

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

5 голосов
/ 05 января 2012

Самое главное, чтобы создать все содержимое таблицы из DOM, а затем вставить в таблицу. Этот в хром заканчивается примерно через 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);
1 голос
/ 05 января 2012

Если у вас есть проверяющая строка 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, "$1$2");
// 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);
0 голосов
/ 05 января 2012

Это определенно выполнимо. Я не думаю, что объединение строк - это путь. В целом, кажется, быстрее создавать элементы и манипулировать ими, когда они не подключены к основному 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, она запускается через <1 секунду, поэтому с вами все будет в порядке. </p>

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