大量数据异步导出的前端解决方案 vuex + 轮询 + 后端任务队列

本文介绍了如何通过改进交互逻辑,解决用户在导出大量数据时长时间等待的问题。通过将导出任务放入后台定时任务,即时反馈任务ID,使用全局下载组件进行状态监测和进度提示,实现了用户可以自由操作而不会被导出过程阻塞的效果,提升了用户体验。
摘要由CSDN通过智能技术生成

问题场景:问题场景是之前运营提出用户导出数据时候等待时间比较久,看怎么解决,由于数据量大,且服务器资源有限,所以优化方向放在了交互逻辑上。

分析问题:面对问题首先进行分析问题,什么原因让用户比较难受?---点了导出按钮就开始转圈,也没有进度条,也不知道好没好,还不能去别的页面,只能一直等下去,,,,,,。。这就是用户的痛点。

寻找方案:了解用户痛点后,开始将问题分块,前端点导出发送请求-----后端接收开始导出数据并生成文件-------后端生成文件完成返回文件url-----前端下载。   看这几个阶段前端几乎没有任何优化空间,后端也是任务繁重,唯一的突破点似乎就是点击导出按钮如何把导出事件放到全局下,不去影响用户使用,以此来解决用户的问题。

梳理逻辑:由于系统中有很多导出需求,所有把这些东西统统集成到一套事件里是不错的选择,所以跟后端商量解决方案,在我的强烈要(乞)求下,最终同意了我的方案。流程逻辑:

  1. 用户点击导出,发送请求给服务器,服务器立即将这个导出任务放到定时任务表里,并立即将任务  id  返回。
  2. 前端点完按钮几乎无延迟的收到了服务器返回的文件id后将id  set到vuex中,然后挂在全局根压面的下载组件监听到vuex改变后就开始轮询服务器导出任务list,查到有任务正在进行中的话,就显示弹窗并一直轮询,由于弹窗是在根组件下,所以不影响用户的使用。
  3. 导出完成,自动执行下载,流程完毕

流程代码:如下

下载文件弹窗组件:    vue + ant     把这个组件放在全局页面下就好  

<template>
  <div>
  </div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import { selectUserDownload, delUserDownload } from '@/api/download'
const key = 'downloadMessage'
export default {
  name: 'PageView',
  data () {
    return {
      a: '',
      selectTime: '',
      downloadName: '',
      timeLength: 1000
    }
  },
  computed: {
    ...mapState({
      download: state => state.user.download
    })
  },
  mounted () {
    this.selectUserState()
    this.timeLength = 1000
  },
  watch: {
    download (newVal, old) {
      if (newVal !== '') {
        this.getPageMeta()
        this.selectUserState()
        this.timeLength = 1000
      } else {
        this.$notification.close('downloadMessage')
        this.Download('')
        clearTimeout(this.selectTime)
      }
    }
  },
  methods: {
    ...mapActions(['Download']),
    getPageMeta () {
      this.$notification.open({
        key,
        message: `文件${this.downloadName}正在后台导出中`,
        description: '系统正在努力为您导出数据,很快就好啦,先喝口水稍等片刻吧!导出完成将会自动下载.',
        icon: <a-icon type="sync" spin />,
        onClose: function () {
          this.Download('')
          this.$notification.close('downloadMessage')
          clearTimeout(this.selectTime)
        },
        duration: 0
      })
    },
    // 文件导出流程   点击下载按钮---》发送请求告诉服务器要下载的文件---》改变vuex中的Dowload值---》监听到vuex中值改变开始轮询查
    // 页面初次加载会执行一次查询请求  返回的list为0就是没有文件下载   有list就是有文件在下载
    // 全局下的查询事件  查询用户下是否有正在下载的文件
    selectUserState () {
      this.selectTime = setTimeout(() => {
        selectUserDownload().then(res => {
          if (res.BusinessData.length !== 0) {
            this.downloadName = `:《${res.BusinessData[0].taskName}"》`
            this.timeLength === 1000 && this.getPageMeta()
            // 设置轮询时长   第一次轮询为  1秒   1秒内没有完成就按照 导出的数据量倍增时长
            // res.BusinessData.forEach(element => {
            if (res.BusinessData[0].status === 1) {
              clearTimeout(this.selectTime)
              window.location.href = res.BusinessData[0].fileUrl
              this.$notification.close('downloadMessage')
              delUserDownload(res.BusinessData[0].taskId).then(res => {})
            } else if (res.BusinessData[0].status === 0) {
              this.selectUserState()
              this.timeLength = 5000
            }
            // })
          } else {
            this.$notification.close('downloadMessage')
            this.Download('')
            clearTimeout(this.selectTime)
          }
        }).catch(err => {
          this.Download('')
          clearTimeout(this.selectTime)
          this.$message.error({
            title: '错误',
            description: err.message
          })
        })
      }, this.timeLength)
    }
  }
}
</script>

<style lang="less" scoped>

</style>

 最终效果:主要思路赘述很多,代码只晒出来大体,剩下的在需要导出的页面改变vuex就好了,前端菜鸡,细节没有修饰,最终完美的解决了用户干等的问题,最终效果就是用户点完导出,立即出现弹框,这时用户可以该干嘛干嘛,导出完成自动下载。

还有就是你觉得这是在分享代码吗?我觉得更重要的是解决问题的思路和前端业余流程追求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值