Jquery 一次循环和绑定 10 条记录
Jquery looping and binding 10 records at a time
我有一个场景,我从服务器获取数千条记录作为JSON,并将所有记录绑定到页面。 对于每条记录,我都在jquery中进行一些计算并将数据绑定到UI。由于记录计数为 1000,因此计算和绑定数据所需的时间更多。当所有记录计算完成后,页面上的数据将绑定到末尾。是否有任何选项可以逐个绑定数据或 10 x 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 个项目绑定数据以确保用户感觉页面已加载,然后将 100 个左右的剩余项目附加到现有列表中。
以简单的方式,您可以分块完成。
<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);
}
如果要保持 UI 响应,并希望能够在渲染大量 DOM 元素之间执行代码,则必须使用超时机制。为此,可以将 render 方法传递给 setTimeout
。
setTimeout
不是将方法添加到堆栈并立即执行,而是将方法推送到任务队列,并且仅在当前 js 堆栈清除后执行它。
我提出的方法的主要步骤:
- 将数据集复制到临时数组
- 使用
splice
从数组中删除前n
项 - 将前
n
项呈现到 DOM - 如果仍有剩余项目,请转到 (2)
这是代码的主要部分,带有注释,假设:
-
testData
保存一系列数据点 -
createRow
保存将数据点转换为呈现的 DOM 元素的逻辑 -
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);
};
在下面的示例中,我包含一个移动微调器,以显示渲染循环如何能够保持适当的帧速率。
请注意,DEFAULT_CHUNK_SIZE
越大,渲染所有项目的速度就越快。权衡:一旦一个渲染块需要超过 1/60 秒,您将失去平滑的帧速率。
// 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);
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;
}
<button class="js-brute">
Inject rows brute force
</button>
<button class="js-to">
Inject rows timeout
</button>
<button class="js-clear">
clear list
</button>
<pre></pre>
<div class="spinner"></div>
<ul>
</ul>
从服务器获取的数据量有问题,你应该找到一种方法来限制数组。
因此,客户端代码可以只处理适当数量的元素,而只是可以向用户显示的元素。
如果这是不可能的,并且您希望在客户端完成所有操作,则应采用更复杂的方法。
您必须保存指向已处理元素的指针,以及一个包含要处理的元素数量的变量(页码?
然后使用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...
}
一种选择是将数据缓冲区拆分为块,以便一次可以对某些数据进行操作。
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();
})();
https://jsfiddle.net/bogfdmfb/1/
构建队列,一次处理几个项目的队列,显示进度,处理队列中的下一个项目等等。
//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();
- 在VanillaJS中模拟模型双向数据绑定
- 无法通过数组映射绑定
- 主干-不管怎样,检查事件以前是否绑定过
- 用于搜索的聚合物嵌套绑定
- Angular:更新一次性绑定的数据
- jQuery.bind或.on习惯于绑定到新记录
- 如何为模型中的类似记录设置另一个名称,以便与ext js中的表单字段进一步绑定
- Ember - 绑定到数组控制器中的过滤列表,然后添加新记录
- Ember.js:live更新不适用于#each绑定到存储记录的子集
- 如何在React中进行两天的数据绑定,当输入值A更新时B更新,反之亦然,同时保留以前转换的历史记录
- 我如何创建一个函数,每次jQuery绑定到单击事件时,它都会详细记录console.log
- 浏览器历史记录返回后未绑定的数据
- 绑定带有单个记录的简单视图模型
- 可观察数组——调用webservice列出所有记录并将其绑定到一个表
- 在ExtJS 4中卸载/解绑定记录的正确方法是什么?
- 实现位置.双向绑定到AJAX记录上下文的散列
- 错误:程序集绑定日志记录已关闭
- 如何在JavaScript中记录超出绑定的ArrayIndex
- Jquery 一次循环和绑定 10 条记录
- js不想绑定我的记录列表,已按位置分组