我有一个场景,我从服务器获得数千条记录作为JSON并将所有记录绑定到页面。对于每条记录,我在jquery中进行一些计算并将数据绑定到UI。由于记录计数为1000,因此计算和绑定数据的时间更长。完成所有记录计算后,页面上的数据将被绑定。是否有任何选项可以逐个或10乘10绑定数据,并在UI上显示该集合的绑定。我想要找到的是一次为10条记录执行$ .each并将下一组10条记录附加到它上面,依此类推。任何想让页面加载更快的想法? (我的要求不需要分页)。任何线索都可以提供帮助。
<div id="keepFinalDataHere"></div>
$.each(data, function (i, record) {
content += "<div>" + record.id + "</div><div>" + record.fromId + "</div><div>" + record.subject + "</div>";
});
$(content).appendTo('#keepFinalDataHere');
在上面的代码中,内容是通过获取数千个记录来构建的,一旦构建了内容,它就被绑定到div。我正在寻找一个选项来获取前10个项目绑定数据,以确保用户感觉页面已加载,然后APPEND剩余项目100个左右的现有列表。
答案 0 :(得分:6)
以简单的方式,你可以分块。
<div id="keepFinalDataHere"></div>
<script>
//.../
var chunkSize = 50;//what ever you want or could be dynamic based on data size
var $keepFinalDataHere = $('#keepFinalDataHere');
$.each(data, function (i, record) {
content += "<div>" + record.id + "</div><div>" + record.fromId + "</div><div>" + record.subject + "</div>";
if(i % chunkSize === 0){ // content chunk is ready
$keepFinalDataHere.append(content); // show records
content = '';//reset the content
}
});
if(!(content === '')){//any leftOver records
$keepFinalDataHere.append(content);
}
答案 1 :(得分:4)
如果您希望保持UI响应并希望能够在呈现大量DOM元素之间执行代码,那么您将不得不使用超时机制。您可以将渲染方法传递给setTimeout
。
不是将方法添加到堆栈并立即执行,T1 { S1 --->U1 }
T2 { S2 ----->U2}
将方法推送到任务队列,只在当前js堆栈清除后才执行它。
我建议的方法的主要步骤:
setTimeout
删除数组中的第一个splice
项n
项呈现给DOM 这里是代码的主要部分,带有注释,假设:
n
包含一系列数据点testData
拥有将数据点转换为渲染DOM元素的逻辑createRow
保存您想要呈现的行数而不会超时。INITIAL_CHUNK_SIZE
保存每个后续循环必须呈现的行数 超时渲染器(DEFAULT_CHUNK_SIZE
):
toRenderer
在下面的示例中,我包含了一个移动微调器,以显示渲染循环如何能够保持合适的帧速率。
请注意,var toRenderer = function(s) {
// We need a copy because `splice` mutates an array
var dataBuffer = [].concat(testData);
var nextRender = function(s) {
// Default value that can be overridden
var chunkSize = s || DEFAULT_CHUNK_SIZE;
dataBuffer
.splice(0, chunkSize)
.forEach(createRow);
if (dataBuffer.length) {
setTimeout(nextRender);
}
};
// Triggers the initial (not timed out) render
nextRender(INITIAL_CHUNK_SIZE);
};
越大,您渲染所有项目的速度就越快。权衡:一旦渲染块超过1/60秒,你就会失去平滑的帧速率。
DEFAULT_CHUNK_SIZE
&#13;
// SETTINGS
var DATA_LENGTH = 10000;
var DEFAULT_CHUNK_SIZE = 100;
var INITIAL_CHUNK_SIZE = 10;
var list = document.querySelector("ul");
var createRow = function(data) {
var div = document.createElement("div");
div.innerHTML = data;
list.appendChild(div);
};
// Blocking until all rows are rendered
var bruteRenderer = function() {
console.time("Brute renderer total time:");
testData.forEach(createRow);
console.timeEnd("Brute renderer total time:");
}
// Pushes "render assignments" to the "task que"
var toRenderer = function(s) {
console.time("Timeout renderer total time:");
var dataBuffer = [].concat(testData);
var nextRender = function(s) {
var chunkSize = s || DEFAULT_CHUNK_SIZE;
dataBuffer
.splice(0, chunkSize)
.forEach(createRow);
if (dataBuffer.length) {
setTimeout(nextRender);
} else {
console.timeEnd("Timeout renderer total time:");
}
};
nextRender(INITIAL_CHUNK_SIZE);
};
// EXAMPLE DATA, EVENT LISTENERS:
// Generate test data
var testData = (function() {
var result = [];
for (var i = 0; i < DATA_LENGTH; i += 1) {
result.push("Item " + i);
}
return result;
}());
var clearList = function() {
list.innerHTML = "";
};
// Attach buttons
document.querySelector(".js-brute").addEventListener("click", bruteRenderer);
document.querySelector(".js-to").addEventListener("click", toRenderer);
document.querySelector(".js-clear").addEventListener("click", clearList);
&#13;
button {
display: inline-block;
margin-right: .5rem;
}
.spinner {
background: red;
border-radius: 50%;
width: 20px;
height: 20px;
animation-duration: 1s;
animation-timing-function: linear;
animation-direction: alternate;
animation-name: move;
animation-iteration-count: infinite;
}
@keyframes move {
from {
transform: translate3d(800%, 0, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}
ul {
height: 200px;
overflow-y: scroll;
background: #efefef;
border: 1px solid #ccc;
}
&#13;
答案 2 :(得分:3)
如果您从服务器获取的数据量有问题,您应该找到一种方法来限制数组。
因此,您的客户端代码只能处理适当数量的元素,只能处理您可以向用户显示的元素。
如果这是不可能的,并且你想在客户端做所有事情,你应该有一个更复杂的方法。
您必须将指针保存到已处理的元素,以及一个包含要处理的元素数量的变量(页面数?)。
然后使用for
循环。
// Globally but not global
var cursor = 0
...
for(var i = cursor; i < (cursor+pageNum); i++) {
var element = myDataAsJsonFromApi[i];
// ... do something here.
}
// check if pageNum elements is added..
cursor += pageNum
if (myDataAsJsonFromApi.length == cursor) {
// load from server...
}
答案 3 :(得分:3)
一种选择是将数据缓冲区拆分为块,这样您就可以一次对某些数据进行操作。
var data = [1,2,3,4,5,6,7,7,8,9,9,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,89];
(function () {
var lastSliceStart = 0;
function writeNext() {
var length = 10;
var chunk = $(data).slice(lastSliceStart, lastSliceStart+length);
$(chunk).each((key, item) => {
console.log(item);
});
lastSliceStart += length;
if (lastSliceStart < data.length) {
setTimeout(writeNext, 500); // Wait .5 seconds between runs
}
}
writeNext();
})();
答案 4 :(得分:3)
一次构建一个队列,处理几个项目的队列,显示进度,处理队列中的下一个项目等等。
//your app
App = {
data: [] //set your JSON dataSource here
}
//define Task
Task = function () {
this.buildQueue(10);
};
Task.prototype = {
buildQueue: function (size) {
var data_count = App.data.length; //length of your datasource
this.queue = [];
// fill the queue
var lastIndex = 0;
var current_index = size;
var c = true;
while (c) {
if (current_index >= data_count - 1) {
current_index = data_count;
c = false;
}
this.queue.push([lastIndex, current_index - 1]);
lastIndex = current_index;
current_index += size;
}
/* If size is 10, array would be [[0,9], [10,19], [20,29]....and so on], The smaller the size, better progress / percentage variation / loading on ui display */
},
doNext: function () {
if (this.queue.length == 0) {
this.end();
return;
}
var row = this.queue.shift(); //stack is LIFO, queue is FIFO, this.queue.pop()
try {
this.processQueue(App.data, row[0], row[1]); //pass dataSource, and indexes of array, loop in processQueue function for indexes passed
} catch (e) {
return;
}
this.incrementProgress(row[1] / App.data.length); //progress on ui
// do next
var _self = this;
setTimeout(function () {
_self.doNext();
}, 1);
},
incrementProgress: function (percent) {
var $progress = $('#percent');
percent = Math.ceil(percent * 100);
percent = percent + '%';
$progress.text(percent);
},
start: function () {
$('#percent').show();
this.doNext(); //initiate loop
},
end: function () {
$('#percent').hide();
},
processQueue: function (data, start, end) {
for (var i = start; i <= end; i++) {
var dataObj = data[i];
//use the data here, update UI so user sees something on screen
}
}
};
//initialize an instance of Task
var _task = new Task(task);
_task.start();