摘要:大文件上传的实现准备阶段大文件上传的过程中需要用到发布订阅模式监听上传的进度发布订阅模式的实现事件栈获取事件对应栈的索引事件类型对应栈的索引不存在为已有事件类型处理栈监听事件自定义事件类型事件处理函数已存在事件类型处理直接把相应的处理函
大文件上传的实现
准备阶段:
大文件上传的过程中需要用到发布订阅模式监听上传的进度
发布订阅模式的实现
export default class { // 事件栈 eventStacks = [{ eventType: "", handlers: [] }]; /** * 获取事件对应栈的索引 * * @param {string} eventType 事件类型 * @return {number} stackIndex 对应栈的索引 不存在为-1 */ indexOf(eventType) { const eventStacks = this.eventStacks; // 已有事件类型处理栈 let stackIndex = -1; for (let i = 0; i < eventStacks.length; i++) { const eventStack = eventStacks[i]; if (eventStack.eventType === eventType) { stackIndex = i; break; } } return stackIndex; }; /** * 监听事件 * * @param {string} eventType 自定义事件类型 * @param {Function} handler 事件处理函数 */ on(eventType, handler) { const index = this.indexOf(eventType); if (index >= 0) { // 已存在事件类型处理 直接把相应的处理函数入栈 this.eventStacks[index].handlers.push(handler); } else { // 不存在事件,把对应的事件处理入栈 const newEventStack = { eventType, handlers: [handler] }; this.eventStacks.push(newEventStack); } }; /** * 触发对应的事件 * * @param {string} eventType 自定义事件类型 * @param {Object} params 参数对象 */ emit(eventType, params = {}) { this.execEvent(eventType, params); }; /** * 执行对应的事件 * * @param {string} eventType 自定义事件类型 * @param {Object} params 参数对象 */ execEvent(eventType, params = {}) { const index = this.indexOf(eventType); if (index < 0) { return; } const handlers = this.eventStacks[index].handlers; for (let i = 0; i < handlers.length; i++) { const currentHandler = handlers[i]; if (currentHandler && typeof currentHandler === "function") { currentHandler(params); } } }; /** * 解除对应的事件 * * @param {string} eventType 事件类型 * @param {Function} handler 事件处理器 必须是引用传进来 使用对象引用相等判断 */ offHandler(eventType, handler) { const index = this.indexOf(eventType); if (index >= 0 && this.eventStacks[index].handlers.length) { // 存在,并且已经入栈 const handlers = this.eventStacks[index].handlers; this.eventStacks[index].handlers = handlers.filter(currentHandler => { return currentHandler !== handler }); } } }
文件是基于Blob BlobMDN文档
Blob 类型可以使用slice截取一段 基于这点 我们就可以吧大文件拆分成很多小的文件块上传 前端实现如下:
import superagent from "superagent"; import eventEmitter from "../util/eventEmitter"; // 上传单个文件 export const uploadFile = (file, url) => { const formData = new FormData(); formData.set("image", file); console.log(file.size); return superagent.post(url) .send(formData); }; // 获取文件分块之后的数量 const getFragmentNum = (file, fragmentSize) => { // fragmentSize 拆分文件的大小 return Math.ceil(file.size / fragmentSize); }; // 获取文件碎片 const getFileFragment = (file, start, end, fragmentSize) => { return file.slice(start * fragmentSize, end * fragmentSize); }; const getSlicedFiles = (file, fragmentSize) => { const slicedFiles = []; // 获取文件分块的数量 const fragmentNum = getFragmentNum(file, fragmentSize); // 获取所有的分块文件 for (let i = 0; i < fragmentNum; i++) { const currentFileFragment = getFileFragment(file, i, i + 1, fragmentSize); slicedFiles.push(currentFileFragment); } return slicedFiles; }; // 多文件上传 export class uploadBigFile extends eventEmitter { constructor(file, url, fragmentSize) { super(); // 拆分的文件数组 const slicedFiles = getSlicedFiles(file, fragmentSize); // 正在上传的模块 this.currentIndex = 0; this.uploadSlicedFiles(slicedFiles, url); }; /** * 上传拆分后的文件 * * @param {Array} files 文件数组 * @param {string} url 上传的地址 */ uploadSlicedFiles(files, url) { uploadFile(files[this.currentIndex], url) .then(({body}) => { this.emit("process", { currentIndex: this.currentIndex, res: body, progress: (this.currentIndex + 1) / files.length }); this.currentIndex++; if (this.currentIndex < files.length) { this.uploadSlicedFiles(files, url); } }) .catch(err => { console.log(err); }); }; }
后端实现如下:
const express = require("express"); const router = express.Router(); const multer = require("multer"); const upload = multer(); // multer用于接受formdata router.post("/upload", upload.single("image"), (req, res) => { res.send({ code: 0, file: req.file.size }); }); module.exports = router;
效果如图 :
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/105510.html
摘要:话前上传大文件上传的教程网上很多但是大部分没给出一个比较完整的出来这个博客给出的是前后端一套完整的解决方案其中前端没有使用第三方上传库希望能帮到有同样需求的朋友们大文件分片上传的好处在这里就不用多说了之前不管是上传单文件还是分片文件上传都是 话前 上传大文件上传的教程网上很多, 但是大部分没给出一个比较完整的出来, 这个博客给出的是前后端一套完整的解决方案, 其中前端没有使用第三方上传...
摘要:大文件上传主要分为三部分,预上传,分块上传,合并上传。可以扩展此对象来控制上传头部。是完成最终的大文件合并上传。修改可以控制发送哪些携带数据。 由于业务需要,需要上传大文件,已有的版本无法处理IE版本,经过调研,百度的 webuploader 支持 IE 浏览器,而且支持计算MD5值,进而可以实现秒传的功能。 大文件上传主要分为三部分,预上传,分块上传,合并上传。 预上传:计算MD5值...
摘要:分片上传主要是前端将一个较大的文件分成等分的几片,标识当前分片是第几片和总共几片,待所有的分片均上传成功的时候,在后台进行合成文件即可。 一、前言 在网站开发中,经常会有上传文件的需求,有的文件size太大直接上传,经常会导致上传过程中耗时太久,大量占用带宽资源,因此有了分片上传。 分片上传主要是前端将一个较大的文件分成等分的几片,标识当前分片是第几片和总共几片,待所有的分片均上传成...
阅读 1095·2021-11-24 10:24
阅读 2583·2021-11-22 13:54
阅读 991·2021-09-24 09:55
阅读 3591·2019-08-30 15:54
阅读 1311·2019-08-30 15:44
阅读 1088·2019-08-30 14:23
阅读 3194·2019-08-29 13:45
阅读 1266·2019-08-29 11:19