分时加载的目的: 在用户体验的极限值去分批加载大型数据.保证浏览器整个数据加载的流畅.避免假死现象.
几点说明:
- timedChunk 函数,里面的 50ms 来自 Response Time Overview 中的调查结果:100ms 内的响应能让用户感觉非常流畅。50ms 是 Nicholas 针对 JavaScript 得出的最佳经验值。
- setTimeout 延时 25ms, 是因为浏览器的时间分辨率问题。25ms 可以保证主流浏览器都顺畅(有喘息的机会去更新 UI)。
- 上面的实例,传统方式加载会让浏览器在加载数据期间,无法更新界面和响应任何操作。采用分时加载,则可以让浏览器始终保持可响应状态,提升界面流畅性和用户体验。
以5000条表格数据为例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> 分时加载 </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
button { width:200px; height:50px; }
#lay {margin:0 auto; width: 670px; }
#userlist { width:502px; border:1px solid #8C8C8C; margin-left:50px; margin-top:10px; height:30px; border-collapse:collapse; font-size:12px; }
#userlist thead td { height:25px; border:1px solid #8C8C8C; text-align:center; background-color:#00CC00; }
#userlist tbody td { height:25px; border:1px solid #8C8C8C; text-align:center; }
</style>
</head>
<body>
<div id="lay">
<button id="resetBtn">重置</button>
<button id="tradBtn">传统加载</button>
<button id="timeBtn">分时加载</button>
<div style="width:500px; border:1px solid #000; background-color:#FFF; margin-left:50px; margin-top:10px; ">
<div id="processBar" style="width:0; height:35px; background-color:#003366; line-height:35px; color:#FFF; "></div>
</div>
<table id="userlist">
<thead><tr><td>用户列表</td></tr></thead>
<tbody></tbody>
</table>
</div>
<script>
var loadDemo = function() {
var $ = function(id) { return document.getElementById(id); },
resetBtn = $('resetBtn'), tradBtn = $('tradBtn'), timeBtn = $('timeBtn'),progress = $('processBar'),
userlist = $('userlist'), tbody = userlist.tBodies[0], i, n = 1, JSON_DATA = [];
// 创建用户列表
function addItem(data) {
var tr = document.createElement('tr');
var td = document.createElement('td');
td.appendChild(document.createTextNode(data[0]));
tr.appendChild(td);
tbody.appendChild(tr);
if(++n % 10 == 0) progressing();
}
// 加载进度
function progressing() {
progress.style.width = (progress.offsetWidth + 1) + 'px';
}
// 清空用户列表
function reset() {
resetBtn.disabled = true;
tradBtn.disabled = false;
timeBtn.disabled = false;
if(window.ActiveXObject) { // IE
var temp = document.createElement('div');
temp.innerHTML = '<table><tbody></tbody></table>';
userlist.replaceChild(temp.firstChild.tBodies[0], tbody);
tbody = userlist.tBodies[0];
} else {
tbody.innerHTML = '';
}
progress.innerHTML = '';
progress.style.width = 0;
n = 1;
}
// 分时函数[*****]
function timedChunk(items, process, context, callback) {
var todo = items.concat(), delay = 25;
setTimeout(function() {
var start = +new Date();
do {
process.call(context, todo.shift());
} while (todo.length > 0 && (+new Date() - start < 50))
if(todo.length > 0) {
setTimeout(arguments.callee, 25);
} else if(callback) {
callback();
}
}, delay);
}
// 分时加载
function testTimed() {
resetBtn.disabled = true;
tradBtn.disabled = true;
timeBtn.disabled = true;
var start = +new Date(), end;
timedChunk(JSON_DATA, addItem, null, function() {
resetBtn.disabled = false;
end = +new Date();
progress.innerHTML = (end - start) + ' ms';
});
}
// 传统加载
function testTrad() {
resetBtn.disabled = true;
tradBtn.disabled = true;
timeBtn.disabled = true;
var start = +new Date(), end;
for(var i = 0, len = JSON_DATA.length; i < len; i++) {
addItem(JSON_DATA[i]);
}
end = +new Date();
resetBtn.disabled = false;
progress.innerHTML = (end - start) + ' ms';
}
return {
run: function() {
// 模拟用户数据
for(i = 1; i <= 5000; i++) {
JSON_DATA.push(['用户名称' + i]);
}
resetBtn.onclick = function() { reset(); }
tradBtn.onclick = function() { testTrad(); }
timeBtn.onclick = function() { testTimed(); }
}
}
}();
loadDemo.run();
</script>
</body>
</html>
参考:
http://www.nczonline.net/blog/2009/08/11/timed-array-processing-in-javascript/