# 如何优雅展示后端传来的10w+数据
- 【首先先完成前置工作】
- 后端搭建
const http = require('http')
http.createServer((req, res) => {
// 开启CORS
res.writeHead(200, {
'Access-Control-Allow-Origin': '*', //允许跨域的域名
'Access-Control-Allow-Methods': 'DELETE,PUT,POST,GET,OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
})
//生成十万条数据
let num = 0;
let list = [];
for (let i = 0; i < 1000; i++) {
num++;
list.push({
src: 'https://p3-passport.byteacctimg.com/img/user-avatar/d71c38d1682c543b33f8d716b3b734ca~300x300.image',
text: `我是${num}号用户`,
tid: num
})
}
res.end(JSON.stringify(list))
}).listen(8000, function () {
console.log('server is running at 8000');
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 前端页面
* {
padding: 0;
margin: 0;
}
#container {
height: 100vh;
overflow: auto;
}
.sunshine {
display: flex;
padding: 10px;
}
img {
width: 150px;
height: 150px;
}
<div id="container"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 另外新建一个js文件实现:封装Ajax请求后端数据、渲染数据
// 封装ajax函数,请求10w条数据
const getList = function () {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest(); //创建异步对象
xhr.open('get', 'http://127.0.0.1:8000')//设置请求的url参数
xhr.onreadystatechange = function () {//注册事件
if (xhr.readyState == 4 && xhr.status == 200) {
resolve(JSON.parse(xhr.responseText))
}
}
xhr.send() //发送请求
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 直接渲染 ×
const renderList = async () => {
console.time('时间');
const list = await getList()
list.forEach(item => {
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `<img src="${item.src}"><span>${item.text}</span>`
container.appendChild(div)
})
console.timeEnd('时间')
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# setTimeout分页渲染
const renderListPage = async () => {
console.time('时间')
const list = await getList()
const total = list.length
const page = 0;
const limit = 200;//每页数据量
const totalPage = Math.ceil(total / limit) //一共有多少页
const render = (page) => {
if (page >= totalPage) return;
//利用定时器,每次渲染1页数据
setTimeout(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = list[i]
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `<img src="${item.src}"><span>${item.text}</span>`
container.appendChild(div)
}
render(page + 1)
}, 0)
}
render(page)
console.timeEnd('时间')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# requestAnimationFrame渲染
// 使用requestAnimationFrame替代setTimeout,可以减少重排次数
const renderListFrame = async () => {
console.time('时间')
const list = await getList();
const page = 0;
const limit = 200;
const total = list.length;
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return;
requestAnimationFrame(() => {
for (let i = page * limit; i < page * limit + limit; i++) { //处理每一页的数据
const item = list[i]
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
container.appendChild(div)
}
render(page + 1)
})
}
render(page)
console.timeEnd('时间')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 文档碎片+requestAnimationFrame渲染
//文档碎片+requestAnimationFrame. 之前是每创建一个div就appendChild一次,现在可以利用文档碎片先把一页的div标签放进文档碎片中,再一次性appendChild到container中,减少appendChild次数
const renderListFragment = async () => {
console.time('时间')
const list = await getList();
const page = 0;
const limit = 200;
const total = list.length;
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return;
requestAnimationFrame(() => {
//创建文档碎片
const fragment = document.createDocumentFragment()
for (let i = page * limit; i < page * limit + limit; i++) { //处理每一页的数据
const item = list[i]
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
//塞进文档碎片
fragment.appendChild(div)
}
//一次性appendChild
container.appendChild(fragment)
render(page + 1)
})
}
render(page)
console.timeEnd('时间')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 懒加载(TODO)
//懒加载。在每一页的底部放一个空节点blank,先渲染第一页数据,向上滚动,等出现blank说明到底了,这时再加载第二页...
renderListLazy = async () => {
}
1
2
3
4
2
3
4
# 虚拟列表(TODO)
参考博客:后端一次给你10万条数据,如何优雅展示
← XSS