后端一次性传了10w条数据,前端该如何处理?——面试高频(代码片段)

欧阳呀 欧阳呀     2022-12-12     335

关键词:

前端处理后端传的10w条数据


1. 这道题在考什么?

  • 对于性能优化的处理方案
  • 对于前端渲染机制的了解
  • 极端情况下的处理及知识领域的广度

2.先用 node.js 整个10w条数据

const http = require('http')
const PORT = 8000

const server = http.createServer((req, res) => 
    res.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;

    for (let i = 0; i < 200; i++) 
        num++;
        list.push(
            src: '图片地址',
            text: `这是第$num张图片`,
            id: num
        )
    
    res.end(JSON.stringify(list))
)

server.listen(PORT, () => 
    console.log('服务跑起来了!')
)

3. 基础代码环境

  • index.html 代码如下
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img
            width: 150px;
        
        .flex
            display: flex;
            padding: 10px;
        
    </style>
</head>
<body>
    <div id="container">

    </div>
    <script src="./index.js"></script>
</body>
</html>
  • index.js 代码如下
const getList = () => 
    return new Promise((resolve, reject) => 
    	// 创建请求
        let ajax = new XMLHttpRequest();
        // 这里请求的是本地服务器
        ajax.open('get', 'http://127.0.0.1:8000');
        ajax.send();
        ajax.onreadystatechange = function()
            if(ajax.readyState == 4 && ajax.status == 200)
                resolve(JSON.parse(ajax.responseText))
            
        
    )

const container = document.getElementById("container")

4. 常规处理方案

const renderList = async () => 
    console.time('列表时间')
    const list = await getList();

    list.forEach( item => 
        const div = document.createElement('div')
        div.className = 'flex'
        div.innerHTML = `<img src="$item.src" /><span>$item.text</span>`
        container.appendChild(div)
    );
    console.timeEnd('列表时间')

renderList()
  • 这种方案就是简单粗暴的循环渲染
  • 此方案耗时大概是 13s
  • 这种做法当然是不可取的,等到天都黑了,用户可能会骂娘

5. 优化的第一种方式 —— 前端分页

const renderList = async () => 
    console.time('列表时间')
    const list = await getList();

    const total = list.length;

    const page = 0;
    const limit = 200;
    // 总页数
    const totalPage = Math.ceil(total / limit);   // Math.ceil 1.1 => 2

    const render = (page) => 
        if(page >= totalPage) return

        setTimeout(() => 
            for(let i = page * limit; i < page * limit + limit; i++)
                const item = list[i];
                const div = document.createElement('div')
                div.className = 'flex'
                div.innerHTML = `<img src="$item.src" /><span>$item.text</span>`
                container.appendChild(div)
            
            render(page + 1)
        , 0)
    
    render(page);
    console.timeEnd('列表时间')

renderList()
  • 思路是把十万条数据分成 10w / 200页,再加上setTimeout,每次渲染一页,速度得到了大幅度提升
  • 方案耗时:不到 1s 搞定

6. 再次优化

const renderList = async () => 
    console.time('列表时间')
    const list = await getList();

    const total = list.length;

    const page = 0;
    const limit = 200;
    // 总页数
    const totalPage = Math.ceil(total / limit);   // Math.ceil 1.1 => 2

    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 = 'flex'
                div.innerHTML = `<img src="$item.src" /><span>$item.text</span>`
                container.appendChild(div)
            
            render(page + 1)
        )
    
    render(page);
    console.timeEnd('列表时间')


renderList()
  • 使用 requestAnimationFrame 代替 setTimeout,减少了重排的次数,极大提高了性能

7. 极致优化(最佳方案)

const renderList = async () => 
    console.time('列表时间')
    const list = await getList();

    const total = list.length;

    const page = 0;
    const limit = 200;
    // 总页数
    const totalPage = Math.ceil(total / limit);   // Math.ceil 1.1 => 2

    const render = (page) => 
        if(page >= totalPage) return

        requestAnimationFrame(() => 
            const fragment = document.createDocumentFragment()
            // 文档碎片 => dom节点 不是在dom树上一部分
            // N次追加 => 1次
            for(let i = page * limit; i < page * limit + limit; i++)
                const item = list[i];
                const div = document.createElement('div')
                div.className = 'flex'
                div.innerHTML = `<img src="$item.src" /><span>$item.text</span>`
                fragment.appendChild(div)
                // container.appendChild(div)
            
            container.appendChild(fragment)
            render(page + 1)
        )
    
    render(page);
    console.timeEnd('列表时间')


renderList()
  • 这里的优化点主要是:之前是创建一个div就追加一次:
div.innerHTML = `<img src="$item.src" /><span>$item.text</span>`
container.appendChild(div)
  • 现在改成一次性追加,极大的提高了性能。
container.appendChild(fragment)

8. 知识点补充

  • window.requestAnimationFrame()
  1. 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
  2. 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行;
  3. 若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
  • DocumentFragments —— 文档碎片
  1. DocumentFragments 是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。
  2. 在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中。
  3. 所以将子元素插入到文档片段时不会引起【页面回流】(对元素位置和几何上的计算)。
  4. 因此,使用文档片段通常会带来更好的性能。

1. 希望本文能对大家有所帮助,如有错误,敬请指出

2. 原创不易,还请各位客官动动发财的小手支持一波(关注、评论、点赞、收藏)
3. 拜谢各位!后续将继续奉献优质好文
4. 如果存在疑问,可以私信我(主页有Q)

后端接口一次返回10万条数据,前端应该如何处理?(代码片段)

...,说实话,这种问题工作中几乎不可能遇到,数据都会进行分页处理,但不排除一些特殊的场景,比如要导出所有数据或是大屏慕展示所有数据什么的,如果遇到这种场景该如何处理呢?1.准备工作1.1.... 查看详情

后端接口一次返回10万条数据,前端应该如何处理?(代码片段)

...,说实话,这种问题工作中几乎不可能遇到,数据都会进行分页处理,但不排除一些特殊的场景,比如要导出所有数据或是大屏慕展示所有数据什么的,如果遇到这种场景该如何处理呢?1.准备工作1.1.... 查看详情

后端接口一次返回10万条数据,前端应该如何处理?(代码片段)

...,说实话,这种问题工作中几乎不可能遇到,数据都会进行分页处理,但不排除一些特殊的场景,比如要导出所有数据或是大屏慕展示所有数据什么的,如果遇到这种场景该如何处理呢?1.准备工作1.1.... 查看详情

Codeigniter:当我插入数据时出现重复键错误,我该如何处理这个错误?

】Codeigniter:当我插入数据时出现重复键错误,我该如何处理这个错误?【英文标题】:Codeigniter:whenIinsertdataI\'mgettingduplicatekeyerror,howcanIhandlethiserror?【发布时间】:2018-03-2011:46:30【问题描述】:当我插入数据时出现重复键错误,... 查看详情

django MultiValueDictKeyError 错误,我该如何处理

...905:31:47【问题描述】:我正在尝试将一个对象保存到我的数据库中,但它抛出了MultiValueDictKeyError错误。问题在于表单,is_private由复选框表示。如果未选中该复选框,则显然没有通过任何 查看详情

unity中的线条类模型闪烁该如何处理?

当相机移动的时候,模型不断的闪烁,不是面重叠,该如何处理让模型不闪烁啊实在不行就使用meshCollider来做碰撞器吧,这样会比较贴近现实的碰撞效果的,但是这个对于计算资源的消耗比较大。如果不苛求,我觉得用一些类似... 查看详情

navicat遇到1130错误该如何处理

用Navicat连接远程MySQL数据库时,有时会出现“Navicatformysql1130错误”,提示错误内容为不允许连接MySQL服务。很多人都以为是防火墙在作怪,其实关掉防火墙依然不能解决这个问题,本教程将为大家介绍NavicatforMySQL1130错误的... 查看详情

如果连接关闭,我该如何处理连接并重新连接?

】如果连接关闭,我该如何处理连接并重新连接?【英文标题】:Howcanihandleconnectionandreconnectifconnectiongotclosed?【发布时间】:2020-10-2803:09:16【问题描述】:我需要此客户端长时间保持连接,我如何确保连接?因为这个问题是相关... 查看详情

我该如何处理这个 Array 对象? (目标-C)

】我该如何处理这个Array对象?(目标-C)【英文标题】:HowcanIhandlethisArrayobject?(Objective-C)【发布时间】:2014-03-0611:36:48【问题描述】:首先我有一个NSDictionary。我执行NSURLRequest并使用请求中的JSON信息加载字典。NSDictionary*json=[NSJ... 查看详情

我该如何处理这个警告:哈希不匹配?

】我该如何处理这个警告:哈希不匹配?【英文标题】:HowcanIdealwiththiswarning:hashmismatch?【发布时间】:2016-04-0705:23:16【问题描述】:更新Xcode7.3并运行项目后,我收到警告:哈希不匹配:此目标文件是针对不同版本构建的模块的... 查看详情

我该如何处理这个问题“TypeError:无法读取未定义的属性'toString'”

】我该如何处理这个问题“TypeError:无法读取未定义的属性\\\'toString\\\'”【英文标题】:howcanidealwiththisproblem"TypeError:Cannotreadproperty\'toString\'ofundefined"我该如何处理这个问题“TypeError:无法读取未定义的属性\'toString\'”【... 查看详情

我该如何处理这个错误:未定义的偏移量:0

】我该如何处理这个错误:未定义的偏移量:0【英文标题】:howcanihandlethiserror:Undefinedoffset:0【发布时间】:2021-01-3009:00:57【问题描述】:我正在制作一个在线学校平台,其中一部分学生可以看到它的课程及其信息..但相关函数... 查看详情

我该如何处理这个 C++ Multimap 问题?

】我该如何处理这个C++Multimap问题?【英文标题】:HowDoIDealWithThisC++MultimapIssue?【发布时间】:2020-02-0917:57:01【问题描述】:我是C++的初学者,正在研究简单的程序,但遇到了一个让我很困惑的问题...基本上我创建了一个多重映... 查看详情

程序员该如何处理人际关系

  程序员该如何处理人际关系,以下峰峰为您分享:  良好的人际关系是一个人获得幸福感的重要指标之一,如果不能维护好与家人、朋友、同事的关系,工作再出色也无法让你快乐。  很多人对程序员的印象都是内向、... 查看详情

sapcrmenterprisesearchinitialload遇到错误该如何处理

InitialLoad:CRM_PRODUCTWebDynproTransaction:ESH_ADMIN_UI_COMPONENTStepstoperform:(1)Action:ScheduleIndexingstartstheindexing(2)CheckviatabJobLogSincetheinitialloadistriggeredviaajobitsnotpossibletosetabreakpointinGenILmethodsandtodebugthroughthecodingeasily.Possiblestep:Findprogramthatisexecutedbyth... 查看详情

casewhen语句报错该如何处理?

本篇文章主要介绍的是casewhen语句报错该如何处理,内容讲解的非常详细,且具有一定的实用价值。对于这方面不清楚的朋友,小杜我希望大家看完之后有所帮助,因此,感兴趣的朋友一定要看完!mysql判... 查看详情

fullgc太过频繁该如何处理

监控工具:jvisualVM、VisaulVM、jprofilerJVM优化书籍:《Java性能优化权威指南》、《深入理解java虚拟机》1.年轻代空间不足2.per Gen(永久代)空间满3.CMS GC时出现promotion failed和concurrent mode failure4.统计得到的Minor ... 查看详情

该函数需要php支持xml,这该如何处理

参考技术Aphp5-xml-5.3.3_2  Thexmlsharedextensionforphpphp5-xmlreader-5.3.3_2Thexmlreadersharedextensionforphpphp5-xmlwriter-5.3.3_2Thexmlwritersharedextensionforphp 查看详情