您现在的位置是:首页 >其他 >针对后端上万条数据(本次bug是两万条数据)请求时间太慢,前端优化方案以及解决过程中出现的问题网站首页其他

针对后端上万条数据(本次bug是两万条数据)请求时间太慢,前端优化方案以及解决过程中出现的问题

❆VE❆ 2024-08-14 00:01:02
简介针对后端上万条数据(本次bug是两万条数据)请求时间太慢,前端优化方案以及解决过程中出现的问题

目录

第一章 前言描述

第二章 问题解决过程

2.1 解析问题原因

2.2 对$.when()的理解

2.3 解决过程

2.3.1 治标未治本(针对sessionStore数据过多时存储不足的情况下:12s+)

2.3.2 将第二个页面的统计放在必经页面处理,之后放存储中(12s+)

2.3.3 开始处理时间很长的问题(同步请求分页接口 12s+ ->8s左右)

2.3.4 处理时间更短(异步请求数据,一边请求一边处理:3s-6s)

2.3.5 中途出现的小插曲(分页以及websocket推送)


第一章 前言描述

  • 描述:工作过程中遇到这么一种情况,有一个账号下的数据量特别的大,有将近两万条数据,原先的 代码并没有考虑到到后续维护的操作,只是将获取所有数据的请求结果放到了临时会话存储里了(sessionStore),然后涉及到需要用到该数据时就从临时存储里面拿数据
  • 只看源代码用到了请求数据的方法有:window.HJWL_API-->请求每个api用、$.when().done(function(){}).then(function(){})-->同时处理多个请求时用

第二章 问题解决过程

2.1 解析问题原因

  • 随着后续甲方增加,对应的数据也会不停的增加,导致后期一个管理员下有上万条数据,当获取设备数据的时候请求处理的时间就会变长
  • 由于用到了临时存储,还有个问题就是当请求到的数据特别多时,会超出内存,导致报错

2.2 对$.when()的理解

针对window.HJWL_API请求有一个点就是每次请求完数据之后已经处理了接口,数据已经获取到了,但是获取到的所有永远都是在整个代码逻辑实现完之后才得到的,导致代码逻辑想要实现的过程中拿不到数据(理解成宏任务呢也不对,疑惑点)

$.when()为我解决了很多麻烦:该方法可以这么理解——$.when()下只执行不同的数据请求的方法,然后在.done下能拿到数据,执行对应的方法

2.3 解决过程

2.3.1 治标未治本(针对sessionStore数据过多时存储不足的情况下:12s+)

当时因为比较急,所以就没有特别深的研究,只是单纯的把两个页面中用到了获取总数的接口增加了进去,从而解决了缓存不足的问题

 HJWL_API.getAllDevice().done(function(res) {  //请求获取所有数据的方法
    self.getAllData(res.list);    //将获取到的数据通过传参进行处理
    loading.close()
})

这里之所以通过传参处理,时因为这个方法请求到的数据都是最后得到的

使用了该方案之后地图页面以及一个统计页面每次都需要请求数据,导致每次加载都需要等很长时间,效果不好

2.3.2 将第二个页面的统计放在必经页面处理,之后放存储中(12s+)

该方案虽然对第二个页面有了很大的优化,但是有个缺陷就是,必须经过第一个页面,这样当有的人不走寻常路也就会造成没有数据渲染,也是个投机取巧的方案

 reloadOption1Data: function (data) {
        ……
       //统计数据的过程……
       sessionStorage.stateTemp = JSON.stringify(stateTemp) //最后将统计结果放到临时存储中
},

2.3.3 开始处理时间很长的问题(同步请求分页接口 12s+ ->8s左右)

  •  跟后端商量提供了一个分页的接口
  • 将代码中许多用到定时器的地方都注释了,这些强制延迟的方法虽然为了拿到数据,现在有分页接口就不需要了(当我把这些处理完之后,请求时间由原来的12秒变成了8秒)-- 这是对当前代码进行的处理,但是8秒不稳定,因为还是获取的所有数据
  • 使用$.when对分页接口拿数据(这时用到的还是同步发送请求)
const pageSize = 2500; //一次请求的数据大小
const countPage = Math.ceil(self.devicesTotal/pageSize); //一共有多少页
var deviceList = [];  // 存放数据
var apiList = []   //存放请求
for(let pageNumber = 1; pageNumber<= countPage; pageNumber++) {  //将所有的请求都获取出来
    apiList.push(HJWL_API.getAllDevice('',pageNumber,pageSize))
}
$.when(  //处理所有的分页获取数据的请求
    ...apiList
).done((...res) => {
    res.forEach((devicePage)=>{ //将每个分页得到的结果合并起来
       deviceList.push(...devicePage[0].page.list)
    })
    self.initCharts();      //执行后续的方法
    self.initMap(res.list);
    self.initMap(deviceList);
    loading.close()
})
    this.firstInit = false
})                 

使用该方放之后基本上稳定在 8秒了

2.3.4 处理时间更短(异步请求数据,一边请求一边处理:3s-6s)

  • 这次就是没发送一次分页请求,处理一次对应的方法,获取对应的数据,让发送第二次请求时,再继续处理对应的方法,从而在地图上有一个动态渲染数据的效果,最终将时间缩短至3-6秒,同时还有动态的效果
  • 这里之所以在请求下才执行方法是因为该请求方法只有对应下才会得到数据处理逻辑,正常都是最后才会展示,会造成拿不到数据
 // 异步分组查询
const pageSize = 2500; //分页大小
const countPage = Math.ceil(self.devicesTotal/pageSize); //总页数
for(let pageNumber = 1; pageNumber<= countPage; pageNumber++) { // 通过循环发送请求,同时每请求成功一次数据处理一些事件
    HJWL_API.getAllDevice('',pageNumber,pageSize).then((res)=>{ //发送请求
        self.devices.push(...res.page.list)
        loading.close()
        ……
        //当存储设备数等于总设备数时,代表获取到了所有设备数据
        if(self.devices.length == self.devicesTotal) {
        this.firstInit = false
        let alamState=0;
        // 将地图中心转到一个告警设备并展示设备信息
        for(let k in self.devices) {
             if(self.devices[k].alarmState>alamState){
                  alamState=self.devices[k].alarmState;
                  if(alamState==1){
                        self.play_mp3();
                        self.showInfoWindow(self.devices[k].id);
                              self.map.setZoomAndCenter(18,
[parseFloat(self.devices[k].longitude),parseFloat(self.devices[k].latitude)]);
                              break;
                         }
                  }
             }
         }
})

2.3.5 中途出现的小插曲(分页以及websocket推送)

  •  当数据不足一页时报错,考虑不周到
const pageSize = 2500; //一次请求的数据大小
const countPage = Math.ceil(self.devicesTotal/pageSize); //一共有多少页
var deviceList = [];  // 存放数据
var apiList = []   //存放请求
for(let pageNumber = 1; pageNumber<= countPage; pageNumber++) {  //将所有的请求都获取出来
    apiList.push(HJWL_API.getAllDevice('',pageNumber,pageSize))
}
$.when(  //处理所有的分页获取数据的请求
    ...apiList
).done((...res) => {
    if(countPage===1){  //添加判断,对不足一页的数据重新赋值
        deviceList.push(...res[0].page.list)
    }else{
        res.forEach((devicePage)=>{
             deviceList.push(...devicePage[0].page.list)
        })
    }
    self.initCharts();      //执行后续的方法
    self.initMap(res.list);
    self.initMap(deviceList);
    loading.close()
})
    this.firstInit = false
})      
  • 由于该地图监听涉及到了webSocket推送,每当有新的数据发生变化时,都会对获取的所有数据进行修改。但是这个webSocket推送在数据请求的时候也会发送请求,并且是如果数组中没有会添加,从而造成每次获取到的数据都不一致。

解决方法:将webSocker的方法放到数据请求完成之后再执行。

 // 异步分组查询
const pageSize = 2500; //分页大小
const countPage = Math.ceil(self.devicesTotal/pageSize); //总页数
for(let pageNumber = 1; pageNumber<= countPage; pageNumber++) { // 通过循环发送请求,同时每请求成功一次数据处理一些事件
    HJWL_API.getAllDevice('',pageNumber,pageSize).then((res)=>{ //发送请求
        self.devices.push(...res.page.list)
        loading.close()
        …… //执行的逻辑
        }
     // 初始化websocket用于监听服务器单个设备状态变化推送
     self.init_socket(); //监听的方法
})

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。