我的发!被后端五万条数据爆破我是怎么处理的
前言
今天面试的时候面试官直接问了一句后端一次性返回10万条
数据给你,你如何处理?,我脑中浮现的第一句话就是拿着物理学圣剑找后端进行 “友好的协商”,谁打赢了听谁的。不过虽然这种情况很少,不过我在实际开发中还真遇到了类似的情况,接下来我将带着大家一些处理方案。
正文
方案一 直接渲染
如果请求到10万条数据直接渲染,页面会卡死的,很显然,这种方式是不可取的。 pass!
async getData() {
this.loading = true;
const res = await axios.get("/api/getData");
this.arr = res.data.data;
this.loading = false;
}
方案二 setTimeout分页渲染
这个方法就是,把10w
按照每页数量limit
分成总共Math.ceil(total / limit)
页,然后利用setTimeout
,每次渲染1页数据,这样的话,渲染出首页数据的时间大大缩减了。
const renderData = async () => {
const Data = await getData()
const total = Data.length
const page = 0
//每页数量
const limit = 200
//总页数
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return
setTimeout(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = Data[i]
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `${item.src}" />${item.text}`
container.appendChild(div)
}
render(page + 1)
}, 0)
}
render(page)
}
方案三 requestAnimationFrame
使用requestAnimationFrame
代替setTimeout
,减少了重排
的次数,极大提高了性能,建议大家在渲染方面多使用requestAnimationFrame
。
const renderData = async () => {
const Data = await getData()
const total = Data.length
const page = 0
//每页数量
const limit = 200
//总页数
const totalPage = Math.ceil(total / limit)
const render = (page) => {
if (page >= totalPage) return
// 使用requestAnimationFrame代替setTimeout
requestAnimationFrame(() => {
for (let i = page * limit; i < page * limit + limit; i++) {
const item = Data[i]
const div = document.createElement('div')
div.className = 'sunshine'
div.innerHTML = `${item.src}" />${item.text}`
container.appendChild(div)
}
render(page + 1)
})
}
render(page)
}
方案四 表格滚动触底加载
原理很简单,就是在列表尾部放一个空节点,然后先渲染第1页数据,向上滚动,等到空节点出现在视图中,就说明到底了,这时候再加载第二页,往后以此类推。
至于怎么判断blank
出现在视图上,可以使用getBoundingClientRect
方法获取top
属性。也可以用 js 的IntersectionObserver
API 来实现
<template>
<div id="container" @scroll="handleScroll" ref="container">
<div class="sunshine" v-for="(item) in showList" :key="item.tid">
<img :src="item.src" />
<span>{{ item.text }}span>
div>
<div ref="blank">div>
div>
template>
方案五 虚拟列表
什么是虚拟列表?
所谓的虚拟列表实际上是前端障眼法的一种表现形式。
看到的好像所有的数据都渲染了,实际上只渲染可视区域的部分罢了。如果10万条数据都渲染,那得需要多少dom节点元素呢?所以我们只给用户看,他当下能看到的如果用户要下拉滚动条或者上拉滚动条再把对应的内容呈现在可视区域内。这样就实现了看着像是所有的dom元素每一条数据都有渲染的障眼法效果了
实现
<template>
<div
class="virtualListWrap"
ref="virtualListWrap"
@scroll="handleScroll"
:style="{ height: itemHeight * count + 'px' }"
>
<div
class="placeholderDom"
:style="{ height: allListData.length * itemHeight + 'px' }"
>div>
<div class="contentList" :style="{ top: topVal }">
<div
v-for="(item, index) in showListData"
:key="index"
class="itemClass"
:style="{ height: itemHeight + 'px' }"
>
{{ item.name }}
div>
div>
<div class="loadingBox" v-show="loading">
<i class="el-icon-loading">i>
<span>loading...span>
div>
div>
template>
作者:笨鸟更要先飞
来源:juejin.cn/post/7338636024212504613
来源:juejin.cn/post/7338636024212504613