机智应对后端一次性返回10万条数据

您所在的位置:网站首页 origin怎么隔几个点取数据 机智应对后端一次性返回10万条数据

机智应对后端一次性返回10万条数据

2023-06-03 07:32| 来源: 网络整理| 查看: 265

目录

问题描述

问题考察点

使用express创建一个十万条数据的接口

点击按钮,发请求,获取数据,渲染到表格上

方案一: 直接渲染所有数据

方案二: 使用定时器分组分批分堆依次渲染(定时加载、分堆思想)

分组分批分堆函数

创建定时器去依次赋值渲染

方案三: 使用requestAnimationFrame替代定时器去做渲染

方案四: 搭配分页组件,前端进行分页(每页展示一堆,分堆思想)

方案五: 表格滚动触底加载(滚动到底,再加载一堆)

在el-table中使用el-table-infinite-scroll指令步骤

案例代码

方案六: 使用无限加载/虚拟列表进行展示

什么是虚拟列表?

写一个简单的虚拟列表

代码

使用vxetable插件实现虚拟列表

安装使用代码

方案七: 开启多线程Web Worker进行操作

方案八: 未雨绸缪,防患于未然

场景模拟

总结

问题描述

面试官:后端一次性返回10万条数据给你,你如何处理?

我:歪嘴一笑,what the f**k!

问题考察点

        看似无厘头的问题,实际上考查候选人「知识的广度和深度」,虽然在工作中这种情况很少遇到...

考察前端如何处理大量数据

考察候选人对于大量数据的性能优化

「考察候选人处理问题的思考方式」(关于这一点,文末会说到,大家继续阅读)

......

        文末会提供完整代码,供大家更好的理解

使用express创建一个十万条数据的接口

若是道友对express相关不太熟悉的话,有空可以看看这一篇全栈文章(还有完整代码哦):《Vue+Express+Mysql全栈项目之增删改查、分页排序导出表格功能》

route.get("/bigData", (req, res) => {   res.header('Access-Control-Allow-Origin', '*'); // 允许跨域   let arr = [] // 定义数组,存放十万条数据   for (let i = 0; i  twoDArr.length - 1) {       console.log("每一项都获取完了");       return;     }     // 5. 使用请求动画帧的方式     requestAnimationFrame(() => {       // 6. 取出一项,就拼接一项(concat也行)       this.arr = [...this.arr, ...twoDArr[page]];       // 7. 这一项搞定,继续下一项       page = page + 1;       // 8. 直至完毕(递归调用,注意结束条件)       use2DArrItem(page);     });   };   // 3. 从二维数组中的第一项,第一堆开始获取并渲染(数组的第一项即索引为0)   use2DArrItem(0);  } 方案四: 搭配分页组件,前端进行分页(每页展示一堆,分堆思想)

        这种方式,笔者曾经遇到过,当时的对应场景是数据量也就几十条,后端直接把几十条数据丢给前端,让前端去分页

后端不做分页的原因是。他当时临时有事情请假了,所以就前端去做分页了。

数据量大的情况下,这种方式,也是一种解决方案

思路也是在所有数据的基础上进行截取

简要代码如下:

getShowTableData() {      // 获取截取开始索引      let begin = (this.pageIndex - 1) * this.pageSize;      // 获取截取结束索引      let end = this.pageIndex * this.pageSize;      // 通过索引去截取,从而展示     this.showTableData = this.allTableData.slice(begin, end);  }

        完整案例代码,请看这篇文章:《后端一次性返回所有的数据,让前端截取展示做分页》

        「实际上,这种大任务拆分成许多小任务,这种方式,做法,应用的思想就是分片的方式(时间),在别的场景,比如大文件上传的时候,也有这种思想,比如一个500MB的大文件,拆分成50个小文件,一个是10MB这样...」

方案五: 表格滚动触底加载(滚动到底,再加载一堆)

        这里重点就是我们需要去判断,何时滚动条触底。判断方式主要有两种

scrollTop + clientHeight >= innerHeight

new MutationObserver()去观测

        目前市面上主流的一些插件的原理,大致是这两种。

        笔者举例的这是,是使用的插件v-el-table-infinite-scroll,本质上这个插件是一个自定义指令。对应npm地址:www.npmjs.com/package/el-…

        当然也有别的插件,如vue-scroller 等:一个意思,不赘述

注意,触底加载也是要分堆的,将发请求获取到的十万条数据,进行分好堆,然后每触底一次,就加载一堆即可

在el-table中使用el-table-infinite-scroll指令步骤

  安装,注意版本号(区分vue2和vue3)

「cnpm install \--save [email protected]

  注册使用指令插件

// 使用无限滚动插件 import elTableInfiniteScroll from 'el-table-infinite-scroll'; Vue.use(elTableInfiniteScroll);

  因为是一个自定义指令,所以直接写在el-table标签上即可

      async load() {     // 触底加载,展示数据... }, 案例代码

  为了方便大家演示,这里笔者直接附上一个案例代码,注意看其中的「步骤」注释即可

                                            // 分堆函数 function averageFn(arr) {   let i = 0;   let result = [];   while (i                                       {{ item.name }}                                    ;;loading...         import axios from "axios"; export default {   data() {     return {       allListData: [], // 所有的数据,比如这个数组存放了十万条数据       itemHeight: 40, // 每一条(项)的高度,比如40像素       count: 10, // 一屏展示几条数据       start: 0, // 开始位置的索引       end: 10, // 结束位置的索引       topVal: 0, // 父元素滚动条滚动,更改子元素对应top定位的值,确保联动       loading: false,     };   },   computed: {     // 从所有的数据allListData中截取需要展示的数据showListData     showListData: function () {       return this.allListData.slice(this.start, this.end);     },   },   async created() {     this.loading = true;     const res = await axios.get("http://ashuai.work:10000/bigData");     this.allListData = res.data.data;     this.loading = false;   },   methods: {     // 滚动这里可以加上节流,减少触发频次     handleScroll() {       /**        * 获取在垂直方向上,滚动条滚动了多少像素距离Element.scrollTop        *        * 滚动的距离除以每一项的高度,即为滚动到了多少项,当然,要取个整数        * 例:滚动4米,一步长0.8米,滚动到第几步,4/0.8 = 第5步(取整好计算)        *        * 又因为我们一次要展示10项,所以知道了起始位置项,再加上结束位置项,        * 就能得出区间了【起始位置, 起始位置 + size项数】==【起始位置, 结束位置】        * */       const scrollTop = this.$refs.virtualListWrap.scrollTop;       this.start = Math.floor(scrollTop / this.itemHeight);       this.end = this.start + this.count;       /**        * 动态更改定位的top值,确保联动,动态展示相应内容        * */       this.topVal = this.$refs.virtualListWrap.scrollTop + "px";     },   }, }; // 虚拟列表容器盒子 .virtualListWrap {   box-sizing: border-box;   width: 240px;   border: solid 1px #000000;   // 开启滚动条   overflow-y: auto;   // 开启相对定位   position: relative;   .contentList {     width: 100%;     height: auto;     // 搭配使用绝对定位     position: absolute;     top: 0;     left: 0;     .itemClass {       box-sizing: border-box;       width: 100%;       height: 40px;       line-height: 40px;       text-align: center;     }     // 奇偶行改一个颜色     .itemClass:nth-child(even) {       background: #c7edcc;     }     .itemClass:nth-child(odd) {       background: pink;     }   }   .loadingBox {     position: absolute;     top: 0;     left: 0;     right: 0;     bottom: 0;     width: 100%;     height: 100%;     background-color: rgba(255, 255, 255, 0.64);     color: green;     display: flex;     justify-content: center;     align-items: center;   } } 使用vxetable插件实现虚拟列表

        如果不是列表,是table表格的话,笔者这里推荐一个好用的UI组件,vxetable,看名字就知道做的是表格相关的业务。其中就包括虚拟列表。

    vue2和vue3版本都支持,性能比较好,官方说:**虚拟滚动(最大可以支撑 5w 列、30w 行)**

        强大!

        官方网站地址:vxetable.cn/v3/#/table/…

安装使用代码

        注意安装版本,笔者使用的版本如下:

    cnpm i xe-utils [email protected] \--save

「main.js」

// 使用VXETable import VXETable from 'vxe-table' import 'vxe-table/lib/style.css' Vue.use(VXETable)

  代码方面也很简单,如下:

                                            import axios from "axios"; export default {   data() {     return {       loading: false,     };   },   async created() {     this.loading = true;     const res = await axios.get("http://ashuai.work:10000/bigData");     this.loading = false;     this.render(res.data.data);   },   methods: {     render(data) {       this.$nextTick(() => {         const $table = this.$refs.xTable1;         $table.loadData(data);       });     },   }, }; 方案七: 开启多线程Web Worker进行操作

        本案例中,使用Web Worker另外开启一个线程去操作代码逻辑,收益并不是特别大(假如使用虚拟滚动列表插件的情况下)

        不过也算是一个拓展的思路吧,面试的时候,倒是可以说一说,提一提。

        对Web Worker不熟悉的道友们,可以看看这篇文章:《性能优化之使用vue-worker插件(基于Web Worker)开启多线程运算提高效率》

方案八: 未雨绸缪,防患于未然

以下为笔者愚见,仅供参考...

在上述解决方案都说完以后,并没有结束。

实际上本题目在考查候选人知识的广度和深度以外,更是考查了候选人的处理问题的思考方式,这一点尤其重要!

就程序员开发工作而言,技术知识点不熟悉,可以快速学习,如文档、谷歌、百度、技术交流群,相关同事都可提供一定的支持

更重要的是看中候选人的思考方式,思维模式

试想,两个候选人实力水平差不多,但是一个只知道埋头苦干,有活就干,不去斟酌;而另外一个却是在用心工作的时候,也会仰望星空,会分析如何干活能够高性价比地完成任务,注重过程与结果

这样的话,哪个更加受欢迎一些呢?

        如果笔者是候选人,笔者在说了上述7种方案以后,会再补充第八种方案:未雨绸缪,防患于未然

场景模拟

面试官随意打量着其手中我的简历,抚须怪叫一声:“小子,后端要一次性返回10万条数据给你,你如何处理?”

我眉毛一挑,歪嘴一笑:“在上述7种方案陈述完以后,我想类似的问题,我们可以从根本上去解决。即第八种方案,「要未雨绸缪,防患于未然」。”

“哦?”面试官心中疑惑,缓缓放下我的简历:“愿闻其详。”

我不紧不慢地答道:“在具体开发工作中,我们在接到一个需求时,在技术评审期间,我们就要和后端去商量比较合适的技术解决方案。这个问题是后端要一次性返回我10万条数据,重点并不在10万条这么多数据,而在于后端为什么要这样做?”

面试官抬头,认真听了起来。

我一字一顿地说道:“除去**业务真正需要这种方案**的话(若是客户要求的,那就没啥好说的,干就完了),后端这样做的原因大致有两种,第一种他不太懂sql的limit语句,但这基本不可能,第二种就是他有事情,随便敷衍写了一下。所以,就是要和他沟通,从大数据量接口请求时长过长,以及过多的dom元素渲染导致性能变差,以及项目的可维护性等角度去沟通,我相信只要正确的沟通,就能从根源上去避免这种不太合理的情况发生。”

面试官又突然狡黠地发问:“要是沟通以后,后端死活不给你分页呢?你咋办?你的沟通无效果!你如何处理!人家不听你的!”似乎是觉得这个问题很刁钻,他双臂抱在胸前,靠在椅背上,等待着我脸上即将绽放的的回答不上来地尴尬笑容。

我内心冷哼一声:雕虫小技...

我盯着面试官的眼睛,认真说道:“如果工作中沟通无效果,要么是我自己沟通语言表达的问题,这一点我会注意,不断提升自己的沟通技巧和说话方式,要么就是...”

我声音扬起了三分:“我沟通的这个人有问题!他工作摸鱼偷懒耍滑!固执己见!为难他人!高高在上!自以为是!这种情况下,我会找到我的直属领导去介入,因为这已经不是项目的需求问题了,而是员工的基本素养问题!”

停顿了一秒,我声音又柔和了几分:“但是,但是我相信咱们公司员工中是绝对没有这样的人存在的,各个都是能力强悍,态度端正的优秀员工。毕竟咱们公司在行业中久负盛名,我也是因此慕名而来的。您说对吧?”

面试官眼中闪过震惊之色,他没有想到我居然把皮球又踢给他了,不过他为了维持形象,旋即恢复了镇定,只是面部肌肉在止不住的微微颤抖。

我又补充道:“实际上在工作中,前端作为比较贴近用户的角色而言,需要和各个岗位的同事进行沟通,比如后端、产品、UI、测试等。我们需要通过合理的沟通方式,去提升工作效率,完成项目,实现自己的价值,为公司创造收益,我想这是每一个员工需要做的,也是必须要做到的。”

面试官又抚须怪叫一声:“小子表现还行,你被录用了!一个月工资2200,自带电脑,无社无金,007工作制,不能偷吃公司零食,以及...”

我:阿哒...

总结

「有效的沟通,源自于解决问题的思维模式,在多数情况下,重要性,大于当下所掌握的技术知识点」

网站效果演示地址:http://ashuai.work:8888/#/bigData

GitHub仓库地址:https://github.com/shuirongshuifu/elementSrcCodeStudy



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3