前端导入大量表格数据到后端 | 青训营笔记

128 阅读2分钟

这是我参与「第四届青训营」笔记创作活动的第4天

掘金中有很多关于前端渲染大量数据的博客和方法, 但却很少提到导入表格数据?

现在我的需求是这样的: 前端管理员需要导入本次所有的用户信息, 大概4000条左右。

最简单的做法是一次性全部给后端, 但 Mysql 执行插入操作也需要时间, 就可能会出现超过60s没有响应,浏览器就自动取消接口。如果是一条一条传入, 那么相当于4000次的交互, 少说也得10~30分钟左右吧。

这里我选择的方案是, 一次性传输300条数据, 并行执行3个请求, 最后总时间大概在8~15s左右。

第一步, 将所有数据拆分成300一组

这里就用 lodash 里的 chunk 方法了, 然后可以在里面进行处理

let arr = _.chunk(
    data.map((item) => {
        item.id = String(item.id);
        item["pwd"] = encryptByAes256(item.id);
        return item;
    }),
    300
);

第二步,有限制的并行执行

这里有两种方法:

  1. 在全局 axios 处加个计数变量和数组, 每当一个请求发出时, 就+1, 完成时-1, 没有发送完的就存到数组, 到最后在检查数据发出剩下的。

第一种方法局限性较大, 且也不能复用, 之后就考虑把它封装出来, 最终是在 《node.js 设计模式》 一书中看到有限制的并行执行。

其函数代码如下

export default class handleTask {
  constructor(maxCount) {
    this.maxCount = maxCount;
    this.pendingTask = []; // 待执行的任务
    this.completed = 0;
    this.count = 0;
  }

  run(task) {
    if (this.count < this.maxCount) {
      this.count++;
      task().then(() => {
        this.count--;
        this.completed++;
        console.log(this.completed);
        if (this.pendingTask.length > 0) {
          this.run(this.pendingTask.shift());
        }
      });
    } else {
      this.pendingTask.push(task);
    }
  }
}

它在构造函数中初始化了 4个变量,

  • maxCount: 并行执行的最大数量
  • pendingTask: 待执行的任务
  • completeted: 完成的个数
  • count: 当前正在执行的个数

原理也很简单:

  • 即每次都判断是否 < maxCount
    • 若小于, 就在执行前给 count++
      • 执行完成后, count--, completed++, 并且检查pendingTask, 有数据的话就执行一个, 因为此时正好空出一个来
    • 若大于, 则推入 pendingTask 数组里

那么使用时, 我可以直接 for + run 方法即可。

for (let i = 0; i < arr.length; i++) {
    han.run(upl(arr[i]));
}

function upl() {
    let slice = Array.prototype.slice;
    let [info] = slice.call(arguments);
    return function () {
        return new Promise((resolve) => {
            stuAdd({ info }).then((res) => {
                resolve();
                console.log(res);
            });
        });
    };
}

因为这里需要调用 2 次(一次传入参数, 一次执行 function), 就简单的进行下封装。

最后, 怎么监听所有请求都完成了呢?

我这里用的是 setInterval 轮询的方式每隔 1s 查询一次, 判断 han.completed === arr.length

总结

关于前端导入大量数据到数据库, 由于自己团队中都是偏前端的, 所以解决方法也是重前端。 如果大家有什么其他更好的方法, 欢迎大家评论留言。

这篇文章已收录到我的个人博客中啦