参考:https://mp.weixin.qq.com/s/a9Cso_nXjLeacilF1rs4zA

前言
如果后端真的返回给前端10万条数据,咱们前端要怎么优雅地展示出来呢?(哈哈假设后端真的能传10万条数据到前端)

前置工作
先把前置工作给做好,后面才能进行测试

后端搭建
新建一个server.js文件,简单起个服务,并返回给前端10w条数据,并通过nodemon server.js开启服务

没有安装nodemon的同学可以先全局安装npm i nodemon -g

// server.jsconst http = require('http')
const port = 8000;http.createServer(function (req, res) {// 开启Corsres.writeHead(200, {//设置允许跨域的域名,也可设置*允许所有域名'Access-Control-Allow-Origin': '*',//跨域允许的请求方法,也可设置*允许所有方法"Access-Control-Allow-Methods": "DELETE,PUT,POST,GET,OPTIONS",//允许的header类型'Access-Control-Allow-Headers': 'Content-Type'})let list = []let num = 0// 生成10万条数据的listfor (let i = 0; i < 100000; 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(port, function () {console.log('server is listening on port ' + port);
})

前端页面
先新建一个index.html


// index.html// 样式
<style>* {padding: 0;margin: 0;}#container {height: 100vh;overflow: auto;}.sunshine {display: flex;padding: 10px;}img {width: 150px;height: 150px;}</style>// html部分
<body><div id="container"></div><script src="./index.js"></script>
</body>

然后新建一个index.js文件,封装一个AJAX函数,用来请求这10w条数据


// index.js// 请求函数
const getList = () => {return new Promise((resolve, reject) => {//步骤一:创建异步对象var ajax = new XMLHttpRequest();//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数ajax.open('get', 'http://127.0.0.1:8000');//步骤三:发送请求ajax.send();//步骤四:注册事件 onreadystatechange 状态改变就会调用ajax.onreadystatechange = function () {if (ajax.readyState == 4 && ajax.status == 200) {//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的resolve(JSON.parse(ajax.responseText))}}})
}

// 获取container对象
const container = document.getElementById(‘container’)
直接渲染
最直接的方式就是直接渲染出来,但是这样的做法肯定是不可取的,因为一次性渲染出10w个节点,是非常耗时间的,咱们可以来看一下耗时,差不多要消耗12秒,非常消耗时间

图片
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(‘列表时间’)
}
renderList()
setTimeout分页渲染
这个方法就是,把10w按照每页数量limit分成总共Math.ceil(total / limit)页,然后利用setTimeout,每次渲染1页数据,这样的话,渲染出首页数据的时间大大缩减了

图片
const renderList = async () => {
console.time(‘列表时间’)
const list = await getList()
console.log(list)
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total / limit)

const render = (page) => {if (page >= totalPage) returnsetTimeout(() => {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('列表时间')

}
requestAnimationFrame
使用requestAnimationFrame代替setTimeout,减少了重排的次数,极大提高了性能,建议大家在渲染方面多使用requestAnimationFrame

const renderList = async () => {
console.time(‘列表时间’)
const list = await getList()
console.log(list)
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total / limit)

const render = (page) => {if (page >= totalPage) return// 使用requestAnimationFrame代替setTimeoutrequestAnimationFrame(() => {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('列表时间')

}
文档碎片 + requestAnimationFrame
文档碎片的好处

1、之前都是每次创建一个div标签就appendChild一次,但是有了文档碎片可以先把1页的div标签先放进文档碎片中,然后一次性appendChild到container中,这样减少了appendChild的次数,极大提高了性能
2、页面只会渲染文档碎片包裹着的元素,而不会渲染文档碎片
const renderList = async () => {
console.time(‘列表时间’)
const list = await getList()
console.log(list)
const total = list.length
const page = 0
const limit = 200
const totalPage = Math.ceil(total / limit)

const render = (page) => {if (page >= totalPage) returnrequestAnimationFrame(() => {// 创建一个文档碎片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)}// 一次性appendChildcontainer.appendChild(fragment)render(page + 1)})
}
render(page)
console.timeEnd('列表时间')

}
懒加载
为了比较通俗的讲解,咱们启动一个vue前端项目,后端服务还是开着

其实实现原理很简单,咱们通过一张图来展示,就是在列表尾部放一个空节点blank,然后先渲染第1页数据,向上滚动,等到blank出现在视图中,就说明到底了,这时候再加载第二页,往后以此类推。

至于怎么判断blank出现在视图上,可以使用getBoundingClientRect方法获取top属性

IntersectionObserver 性能更好,但是我这里就拿getBoundingClientRect来举例

图片

《结合“康熙选秀”,给大家讲讲“虚拟列表”》(https://juejin.cn/post/6966179727329460232)

前端渲染10w条数据相关推荐

  1. 后端一次性传了10w条数据,前端该如何处理?—— 面试高频

    前端处理后端传的10w条数据 1. 这道题在考什么? 2.先用 node.js 整个10w条数据 3. 基础代码环境 4. 常规处理方案 5. 优化的第一种方式 -- 前端分页 6. 再次优化 7. ...

  2. mysql虚拟列表_「前端进阶」高性能渲染十万条数据(虚拟列表)

    前言 在工作中,有时会遇到需要一些不能使用分页方式来加载列表数据的业务情况,对于此,我们称这种列表叫做长列表.比如,在一些外汇交易系统中,前端会实时的展示用户的持仓情况(收益.亏损.手数等),此时对于 ...

  3. 在vue中如何高性能渲染十万条数据(虚拟列表)并且增加个搜索框可以搜索到这些数据

    在工作中,有时会遇到需要一些不能使用分页方式来加载列表数据的业务情况,对于此,我们称这种列表叫做长列表.比如,在一些外汇交易系统中,前端会实时的展示用户的持仓情况(收益.亏损.手数等),此时对于用户的 ...

  4. 前端 传表格多条数据 给后台接收 (HTML前端表格多条数据JSON封装后;异步提交到后台处理)

    前端 传表格多条数据 给后台接收 (HTML前端表格多条数据JSON封装后:异步提交到后台处理) 1.多条数据采用checkBox 携带 //封装数据的对象var PayObj = { O_NBR:& ...

  5. 公司新来个同事,MyBatis批量插入10w条数据仅用2秒,拍案叫绝!

    批量插入功能是我们日常工作中比较常见的业务功能之一,今天咱们来一个 MyBatis 批量插入的汇总篇,同时对 3 种实现方法做一个性能测试,以及相应的原理分析. 先来简单说一下 3 种批量插入功能分别 ...

  6. Mysql 批量插入大量数据的两种方案以及优缺点(分别是 5W 条数据和 10W 条数据)

    Mysql 批量插入(5W 条数据和 10W 条数据) 1.批量插入思路 一般是有两种不同的思路: 1.for 循环批量插入 2.生成一条 SQL 语句,比如 insert into user(id, ...

  7. 前端如何处理后端一次性传来的10w条数据

    因为之前在看到了这样的文章,博主介绍了很多种实现方式,作为一名菜鸟级选手,我选择了其中一种实践了一下,因为在平时的项目中其实只需要熟练掌握一种就可以了(( • ̀ω•́ )✧还有就是我是菜鸟~) 懒加 ...

  8. 模拟如何渲染100000条数据

    此类容与掘金同步Fatcat 身为前端程序员的我.一直在做着基础的增删改查. 今天看了个帖子. 说是如果有十万条数据.该如何渲染到页面而不会使其页面死机. 在这里我们可以用类似分页的效果来实现十万条数 ...

  9. 微信小程序 使用.wxs在.wxml中分割字符串渲染多条数据

    在开发微信小程序的项目中,由于接口中有一个字段的值以符号作为分隔,存放了多个value需要在前端展示(例如下图中的good_field字段). 需求效果图 首先这是一个循环渲染出来列表,我无法在这整个 ...

最新文章

  1. 【OpenCV 4开发详解】图像连接
  2. Python Web实时消息后台服务器推送技术---GoEasy
  3. 如何在MDI中相同的子窗体只保留一个实例
  4. JS脚本病毒调试脚本-Trojan[Downloader]:JS/Nemucod
  5. [GO]append的扩容
  6. 虚拟化与Docker
  7. Http Module 介绍
  8. bcp导入到数据库_Bcp和链接到Azure的服务器
  9. 神奇的for循环,让你的for循环执行100w + 1比100w次快200w倍
  10. 【异常:Could not resolve】react-native run-android
  11. python_generator生成器
  12. 在计算机里分数线怎么表示什么意思,高考投档分数线是什么意思 怎么定的
  13. 图像语义分割(10)-DeepLabV3+: 用于图像语义分割的带有空洞可分离卷积的编解码结构
  14. java二维数组详解
  15. matlab gaot工具箱安装详细说明
  16. 使用融云 SDK 避坑指南之 iOS13 推送失败
  17. DM420步进电机驱动器
  18. python 饼图笔记 两个饼图 双饼图 复合饼图 两个饼图 环形图
  19. C语言报错:「error」Id returned 1 exit status
  20. 40个常见的HTML5 面试问题及答案

热门文章

  1. 如何解决“access violation at address”错误
  2. PingCAP 入选 CB Insights 中国「数据链路安全领航者」榜单,保障全球用户存储安全
  3. John密码破解工具
  4. 【专家访谈】测试专家 陈林钧 访谈问题收集中
  5. Zstack home 1.2.2a兼容对接ZHA标准设备和2.5.1a私有设备
  6. 苹果照片未删却不见了_iPhone手机照片不见的解决方法
  7. 分析程序员为什么单身
  8. java-线程安全问题,线程实现线程同步,线程状态,等待唤醒机制,生产者消费者模型
  9. file和folder的区别是什么?
  10. backtrader量化回测,基础篇,附MACD交易回测代码