前段时间有朋友问我一个他们公司遇到的问题, 说是后端由于某种原因没有完成分页功用, 所以一次性返回了2万条数据,让前端用select组件展现到用户界面里. 我听完之后立马明白了他的困惑, 如果经过硬编码的方法去直接烘托这两万条数据到select中,肯定会卡死. 后面他还说需求支撑查找, 也是前端来完成,我登时产生了爱好. 其时想到的计划大致如下:7 ^ ] + _ E

  1. 选用懒加载+分页(前端保护懒加载的数据分发和分页)
  2. 运用虚拟翻滚技能(现在react的antd4.0已支撑虚拟c 3 k翻滚的select长列表)

懒加载和分页方法一般用于做长列表优化, 类似于表格的分页功用, 详细思路就是用户每次只加载能看见的数据,t K N ) S _ g ? { 当翻滚到底部时再去加载下一页的数据.

虚拟翻滚技能也可以用来优化长列表, 其间心思路就是每次只烘托可视区域的列表数,当翻滚后动态的追加元素并经过顶部padding来撑起整个翻滚内容,完成思路也十分简略.

经过以上剖析其实已经可以处理朋友的问题了,可是最为一名有追求的前端工程师, 笔者仔细梳理了一下,7 A T . + – a并根据第一种计划抽象出一个实d ] M I ]践的问题:

如何烘托大数据列表并支撑查找功用?

笔者将经过模仿不同段位前端工程师的完成计划, 来探索一下该问题的价值. 希望能对咱们有所启发, 学会真正的深化思考.

正文

笔者将经过不同经验程序员的技能视角来剖析以上问题, 接下来开端咱们的扮演.

在开端代0 U ? v t码之前咱们先做好基础s – F D准备, 笔者先用no2 / * p m I D Tdejs搭建一个数据服务器, 提供根本的E ( : Z f T z` i G ) [据恳求,中心代码如下:

app.use(async (ctx, next) => {
ifg R u(ctx.url === '/api/getMock') {
let list = [I n 6 $ _ ] J ]
// 生成指定个数的- q Q V随机字符串
function genrateRandomWords(n) {
let words = 'abcdefghijklmnopqrstuvwL E 6 ] txyz你是好的嗯气短前端后端设计产品网但考虑到付款啦分手快乐的分类开发商的李开复封疆大吏师德师风S C a t O M 4吉林省邻近',
len = words.leng% * vth,
ret = ''
for(let i=0; i< n; i++) {
ret += words[Math.floor(Math.random() * len)]
}
return ret
}
// 生成10万条数据的list
for(let i = 0; i< 100000; i++) {
list.k w | 0 3push({
name: `xu_0${i}`,
title: genrateRandomWR K h 3 [ords(12),
text: `我是[  ? @ |${i}项目, 赶快吧~~`,
tid: `xx0 m j_${i}`
})
}
ctx.body = {
state: 200,
data: list
}
}
await 4 |t next()
})8 ) B 5 S

以上笔者是选用koa完成的根本的mock数据服务器, 这样咱们就可以模仿真实的后端环境来开端咱们的前端开发啦(当然V k C C A # j Q也可以直接在前端手动生成10万条数据). 其间genrateRandomWords方法用来生成指定个数的字符串,这在mock数据技能中运用很多, 感爱好的盆友可以学习了解一下. 接下来的前端代码笔者统一选用react来完成(vue同理).

初级工程师的计划

直接从后端恳求数据, 烘托到页面的硬编码计划,思路如下:

当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

代码可能是这样的:

  1. 恳求后端数据:
fetch(`${SERVER_URL}/api/getMock`).then(res => res.json()).then(res => {
if(res.state) {
data! k + = res.data
setList(data)
}
})
  1. 烘托页面
{
list.map((item, i) => {
return <div className={styles.item} key={item.tid}>
<div className={styles.tit}>{item.title} <span className={styles.label}>{item.name}</span></div>
<div>{itemm 8 Q { }.text}</d w / : oiv>
</div>
})
}
  1. 查找数据
consty j ` 1 p 5 D handleSearch = (v) => {
let searchR - ^ F  K ? , oData = data.fX q S Eilter(K c & p t V(item, i) => {
retur, ! a # ! | A v ,n item.title.indexOf(v) > -1
})
setList(searchData)
}

这样9 5 R u s 7 M做本质上是可以完成根本的需求,可是有显着的缺点,那就是数据一次性烘托到页面中, 数据量庞大将导致页面功能极具降低, 形成页面卡顿. S | ~ H 3 H.

中级工程师的计划

作为一名有必定经验的前端开发工程师,必定对页面功能有所了解, 所以必定会熟悉O 3 , B F [ $ J防抖函数节省函数, 并运用过比方懒加载分页这样的计划, 接下来咱们看看中级工程师的计划:

当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

& P = 3 n r A过这个进程的优化, 代码已经根本可用了, 下面来介绍详细完成x p L ) n c =计划:

  1. 懒加载+分页计划
    懒加载的完成主要是经过监听窗口的翻滚, 当某一个占位元素可见之后去加载下一个数据,原理如下:

    当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

    这儿咱们经过监听win$ , 3 k ldowscroll0 t # 2件以及对poll元素运用getBoundingClientRect来获取poll元G 4 s素相关于可视窗口的间隔, 然后自己完成一个懒加载计划.

在翻C ) K 1滚的进程汇总咱% W k t V们还需求注意一个问题就是当用户往回翻滚时, 实践上是不需求做任何处理的,所以咱们需求加一个单向锁, 详细代码如下:J r 3 p G u N W

function scrollAndLoz k a 5 Z 4adinw U Ug() {
ift s v q # s o S(window.scrollY > prevY) {  // 判断用户是否向下翻滚
prevY = window.scrollY
if(poll.current.getBoundingClientRect().top <= window.innerHeight) {
// 恳求下一页数据
}
}
}
useEffect(() => {
// something code
cons. ) # 1 N Rt getData = debounce(scrollAndLoada O w @ Ming, 300)
window.addEventListener('scroll', getData, false)
return () => {
window.removeEventListener('scroll', getData, false)
}{ t J S ` ` u M W
}, [])

其间prevY存储的是窗口s ~ z上一次翻滚的间隔, 只有在向下翻滚而且翻滚高度大于上一次时才更新其值D U t E P e B N.

至于分页的逻辑, 原生javascript完成分页也很简略, 咱们经过I 6 y E定义几个维度:

  • curP@ m e Y m 7 c 2age当时的页数F & i i n
  • pageSize 每一页% A |展现的数量
  • data 传入的数据量

有了这几个条件,咱们的根本能分页功用就可以完成了. 前端v 7 d Q b分页的中心代_ r & – N码如下:

let data = [];
let curPage = 1;
let pageSize = 16;
let prevY = 0;
// other code...
function scrollAndLoading() {
if(window.scrolX u @ N @lY > prevY) {  // 判断用户是否向下翻滚
prevY =2 h I 7 window.scro. 6 4 d | . 0 illY
if(poll.current.getBoundingCliQ Y o g G ventRect().t2 C  N l y zop <= wind3 7 A ~ ? 2o! f C % l 1 d r |w.innerHeight) {
curPage++
setList(searchDa3 Q ^ g m 5 s #ta.slice(0, page: [ j b j 5Size * curPage))
}
}
}
  1. 防抖函数完成
    防抖函数由于比较简略, 这儿直接上一个简略的防抖函数代码:
function debounce(fn, time) {
return function(args) {
let that = this
clearTimeout(fnI V ` | ; P 5.tid)
fn.tid = setTimeout(() => {
fn.call(that, args)
}, time);
}
}
  1. 查找完成
    查找功用代码! N v V T如下:
co~ O o hnst handleSearch = (v) => {
curPa& 6 + F F J # [ge = 1;
prevY = 0;
searchData = data.filter((item, i) => {
// 选用正则来做匹配, 后期支撑前端模糊查找
let reg = new RegExp(v, 'gi')
return reg.test(item.title)
})
seY u & Z JtList(searchData.slicZ v O &  | y | ae(0, pageSize * cb _ x  j b | Z rurPage))
}

R ! . A求结合分页来完成, 所以这儿为d z 0 w P . Y了不影响源数据, 咱们选用临时数据searA J U ochData来存储.
作用如下:

当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

查找后:

当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

无论是查找前仍是查找后, 都利用了懒加载, 所以再也不用忧虑数据量大带来的功i r j T能瓶颈了~

高级工程师的计划

作为一名久经战场的程序员, 咱们应该考虑更高雅的完o ^ : ` : f & e &成方法,比方组件化, 算法优化, 多线程这类问题, 就比方咱们问题中的大数据烘托, 咱们也可以用x ` X / E I O :虚拟长列表来更高雅简洁的来处理咱们的需求. 至于虚拟长9 q * L u 4 : 8 U列表的完成笔者在最初已经点过,这儿就不详细介绍了, 关于更很多的数据,比方100万(尽管实践开发中不会& b X 2 q遇到这么无脑的场景),咱们又该怎么处理呢?

第一个点咱们可以运用js缓冲器来分片处理100万条数据, 思路代码如下:

function multistep(steps,args,callback){
var tasks = ste] c # C S 8 yps.concat();
setTimeout(function(){
var task = tasks.shift();
task.apply(null, args || []);{ b x . : E   //调用Apply参数必须是数组
if(tasks.length > 0){
setTimeout(argumentsQ S o 2 a.callee, 25);
}else{
callback();
}
},25);
}

这样就能比较很多核算导致的js进程阻V K ) _ q P r A塞问题了.更多功能优化计划可以参阅笔者之前的文章:

  • web功能优化的15条实用技巧

咱们还可以经过web worker来将需求在前端进行很多核算的逻辑移入进去, 确保js主进程的快速呼应, 让web worker线程在后台核算, 核算完成后再经过web woN r ( – arker的通讯@ ? h l s : Q机制来通知主进程, 比方模糊查找等, 咱们还可以对查找算法进一步优化,比方二分法等,所以这些都是高级工程师该考虑的问题. 可是必定要分清场景, 寻找出性价比更高的计划.R – , j

最后

如果想学习更多前端技能,实战学习路线, 欢迎在大众号《趣谈前端》加入咱们的技能c P p m F W )群一同学习讨论,共同探索前端的边界。

当后端一次性丢给你10万条数据, 作为前端工程师的你,要怎么处理?

更多推荐

  • 根据react/vue开发一个专归于程序员的朋友圈运用
  • 根据Apify+node+re; % O | _ k jact/vue搭建一个有点意思的爬虫渠道
  • 根据react搭建一个通用的表单办理( d X S d : C 0装备渠道(vue同)
  • 程序员必备的几种常见排序算法和查找算法总结
  • 几个十分有意思i 1 # )的javascript知识点总结
  • 前端进阶之从零到一完成单向 & 双C O [ /向链表
  • 微前端架构初探以及我的前端技能盘点
  • 运用nodZ w y ` & ! [ i ~eJs开发自己的图床运用
  • 根据noz F 3deJS从0到] ( ? 0 e 3 P u1完成一个CMS全栈项目(上)
  • 根据nodeJS从0到1完成一个CMS全栈项目(中)(含源码)
  • CMS全栈项目之Vue和React篇(下)(含源码)
  • 5分钟C H教你用nodeJS手写一个mock数据服务器
  • 从零到一教你根据vue开发一个组件库
  • 从0到1教你搭建前端团队% : r `的组} z * Q l a &件系统(高级进阶必备)
  • 10分钟教你手写8个常用的自定义hooks
  • 15分钟# v m L 3 P带你5 0 * 2 * b了解A L ; w J N A w前端工程师必知的javascript设计形式(附详细思维导图和源码)
  • 《前端实战总结》之运用pos– = { _ ^ .tMes+ = .sage完成可插R O 0拔的跨域聊天机器人