我有一些代码从数据库加载大约5,000行数据。一旦AJAX调用获取行,它就会将它们传递给我的函数来创建行。这个函数遍历JSON数据,创建我们的TR,进行一些查找,然后最终将完整的连接输出附加到DOM。
在文档加载时,我获取1,000条记录并将其附加到用户的DOM中,以便他们可以看到一些数据。然后我在幕后进行AJAX调用以获取其余部分,并在完成后附加它。浏览器在此期间锁定,但是在循环数据时。
在我的测试期间,我评论了each loop
并且问题消失了,所以我把它缩小到了那个范围。我只是不确定如何改进它或者getObjects
的查找功能是否会延迟它。
在下面的代码示例中,缓慢从$(data['data']['results']['data']).each(function() {
开始,至少,这是我注释掉的代码块并且运行顺利。
如果没有让问题过于开放以解决问题,我可以从$.each
循环中除了可以改善这一点的其他选项,还是循环内发生的可能导致缓慢的事情?
// Given data, create our table rows
function createRows(data) {
// Define our vars
var output = '',
markup = '';
// Add the fields we chose to export to the array
// We will then check this array when printing the columns to see if it should be shown or not
if (isset(data.data.exportFields)) {
$(data.data.exportFields.export).each(function() {
exportFields.push(this.fieldID);
});
}
// Loop over the core data
$(data['data']['results']['data']).each(function() {
// First level of data in our XML output
core = $(this)[0];
// Loop over our fields
$(core['fields']['data']).each(function() {
// Set a var for the field level data
field = $(this)[0];
// Do we have markup?
if (isset(data.data.markup)) {
markup = '';
if (typeof getObjects(data.data.markup.data, 'QID', core.QID)[0] !== 'undefined') {
markup = getObjects(data.data.markup.data, 'QID', core.QID)[0].markup;
}
}
output += '<tr class="primaryValue ' + markup + '" data-qid="' + core.QID + '">';
// Loop over all the other rows 2 through x
$.each(field, function(key, value) {
// Field Name Lookup
key = key.replace(/_/gi, '');
FieldNameLookup = getObjects(cfgFields.data.fields.options, 'FieldID', key)[0];
x = FieldNameLookup.FieldName;
val = (value.length ? value : '-')
// Is this an email address?
if (x.match(/email/gi)) {
output += '<td data-tableexport-display="always" class="small ' + (jQuery.inArray(key, exportFields) != -1 ? 'hidden' : '') + '">';
output += '<a href="mailto:' + val + '" class="">' + val + '</a>';
output += '</td>';
} else if (x.match(/NTID/gi)) {
output += '<td data-tableexport-display="always" class="small ' + (jQuery.inArray(key, exportFields) != -1 ? 'hidden' : '') + '">';
output += '<a href="https://website.com/profile/' + val + '" target="_BLANK" class="">' + val + '</a>';
output += '</td>';
} else {
output += '<td data-tableexport-display="always" class="small ' + (jQuery.inArray(key, exportFields) != -1 ? 'hidden' : '') + ' allowContext">';
output += val;
output += '</td>';
}
});
// End our row
output += '<td data-tableexport-display="always" class="notesTD allowContext hidden"></td>';
output += '</tr>'
});
});
// Append the results to the DOM
$('[name=resultsTable]').append(output);
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else if (i == key && obj[key] == val) {
objects.push(obj);
}
}
return objects;
}
答案 0 :(得分:1)
这里有几件事。你有三层嵌套循环。循环越多,嵌套循环越多。将循环分解为自己的函数可能是最有效的,因为它们有自己的目的。以这种方式修改和推理它们会更容易。主要原因是,即使您可能带回1,000条记录,内部循环也必须根据它们所馈送的数组的长度来完成。
我认为另一个慢点是你创建DOM元素的方式。您可以使用纯JavaScript的jQuery创建它们,并将它们缓存在变量中,而不是在字符串中创建它们并将它们连接在一起。您可以在循环中填充其属性和内容。
Javascript BEST PRACTICES PART 2
答案 1 :(得分:0)
正如一些评论建议的那样,无限滚动在这里是个不错的选择。它减少了获取数据,处理数据然后显示数据的时间。 https://www.sitepoint.com/jquery-infinite-scrolling-demos/
我不知道您的数据是否可行,但我在移动应用程序中遇到了类似的问题,我只是将数据分成几类。然后我只根据类别加载数据。
答案 2 :(得分:0)
我建议将循环分解为更小的函数(甚至可能是递归函数),并将html作为节点传递,而不是作为文本传递(因此浏览器不需要重新渲染)。
像这样,但你必须填写一些空白:
function makeTd() {
var hidden = exportFields.indexOf(key) > -1 ? "hidden" : "";
var td = document.createElement('td');
td.setAttribute('data-tableexport-display', 'always');
td.className = "small";
// conditionals for email, etc.
return td;
}
function makeTr() {
var tr = document.creatElement('tr');
tr.className = "primaryValue";
// logic ...
return tr
}
$data.map(function(core, ci){
core.map(function(field, fi) {
var tr = makeTr();
Object.key(field).map(function(output) {
var key = output;
var value = field[output];
var td = makeTd(key, value);
tr.appendChild(td);
});
var endTd = document.createElement('td');
tr.appendChild(endTd);
});
});