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, "&")
.replace(/</g, "<");
// 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, он запускается через