项目背景
身处小公司,公司从别的地方购买了一个20年前的破旧jsp项目(醉了),历经七八代人之手,里面只有更乱,没有最乱,只有你想象不到的乱。没有babel,没有webpack,唯一有的是iframe+jQuery+tomcat+eclipse(iframe嵌套七八层那是常像,还要处理eclipse启动报错啊)。绝望...
分片上传核心代码
[AppleScript] 纯文本查看 复制代码 function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(blobOrFile);
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
var blob = this.files[0];
var BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
var SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while(start < SIZE) {
upload(blob.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
}
}, false);
上传前后的破事处理(结合业务)
后台的文件接收,只能是同步的形式,异步的合并文件就报错,无语...本着优化的心态,那就做个队列吧 切片的上传,关键参数是切片的index,后台根据切片的index进行文件合并
文件类型检测
文件大小检测(我问产品给个限制,产品说不用,再我的再三要求下,他们给了10G...)
解析zip文件的子文件(FileReader处理,不是本次文章的关键,不细说)
获取文件MD5值(github.com/satazor/js-…)
创建上传任务(获取taskid) - creatModelTask
生成上传任务队列 - createQueueArr
处理队列,分片上传 - handleQueueArr+fileUpload
上传完毕,发起文件合并请求 - handleMerge
上传
[AppleScript] 纯文本查看 复制代码 function UploadModel() {
this.DOM = {
uploadModelInputFile: document.querySelector("#uploadModelInputFile") // 模型上传input
}
this.uploadConfig = {
maxFileSize: 10 * 1024 * 1024 * 1024, // 文件最大值
acceptFileTypes: ["zip", "rvt", "dwg"], // 接收的文件类型
BYTES_PER_CHUNK: 3 * 1024 * 1024 // 切片大小3M
}
this.uploadModelArgs = {
fileBlob: null, // 选择的文件
modelName: null, // 文件名称
md5: null, // 文件MD5
fileSuffix: null, // 文件后缀(带点)
fileCountTotal: null, // 切块总数量
taskId: null // 创建上传任务获取到的任务id
}
this.api = {
modelUpload_upload: function (formData) { // 上传
return $.ajax({
type: "POST",
url: publicJS.tomcat_url_one + '/modelUpload_upload.action',
data: formData,
// dataType: "json",
Accept: 'text/html;charset=UTF-8',
// async: false,
processData: false, // 不处理数据
contentType: false, // 不设置内容类型
});
}
}
UploadModel.prototype = {
creatModelTask: function() { // 创建上传任务 },
setUploadPercent: function(fileIndex, fileCountTotal) { // 设置上传进度条
var percent = Math.ceil(fileIndex / fileCountTotal * 100);
percent = percent > 100 ? 100 : percent;
console.log("上传进度==>", percent + "%", "fileIndex===>", fileIndex, "fileCountTotal===>", fileCountTotal);
},
createQueueArr: function(taskId) { // 上传处理,生成任务队列
var start = 0;
var end = _this.uploadConfig.BYTES_PER_CHUNK;
var fileSize = _this.uploadModelArgs.fileBlob.size;
var fileIndex = 0;
var queueArr = []; // 上传任务队列
while (start < fileSize) {
var fd = new FormData();
var chunk = _this.uploadModelArgs.fileBlob.slice(start, end); // 切割chunk
console.log(chunk);
fd.append('taskid', taskId);
fd.append('fileIndex', fileIndex);
fd.append('fileItemSplit', chunk);
queueArr.push(_this.fileUpload.bind(_this, fd, fileIndex, _this.uploadModelArgs.fileCountTotal));
fileIndex++;
start = end;
end = start + _this.uploadConfig.BYTES_PER_CHUNK;
};
return queueArr;
},
handleQueueArr: function(queueArr) { // 处理任务队列
// https://github.com/mqyqingfeng/Blog/issues/90
if (Array.isArray(queueArr) && queueArr.length > 0) {
// 创建迭代器协议(非可迭代协议)
var iterator = {
queueArr: queueArr,
nextIndex: 0,
next() {
return this.nextIndex < this.queueArr.length ? {
value: this.queueArr[this.nextIndex++],
done: false
} : {
value: this.queueArr[this.nextIndex++],
done: true
}
}
};
var exectorIterator = function () {
var obj = iterator.next();
if (!obj.done) {
if (typeof obj.value === 'function') {
obj.value()
.then(function () {
exectorIterator(); // 递归
}, function (error) {
console.log(error);
console.log("文件上传失败,请重试")
})
}
}
}
exectorIterator();
},
/**
* 分片上传
* @param {FormData} fd 上传参数
* @param {Number} fileIndex 当前切片index
* @param {Number} fileCountTotal 切片总数
* @param {Element} uploadPercentProgress 进度条DOM节点
*/
fileUpload: function (fd, fileIndex, fileCountTotal) {
var _this = this;
return new Promise(function (resolve, reject) {
_this.api.modelUpload_upload(fd)
.then(function (res) {
if(utils.isObject(res) && utils.hasOwnProperty(res, "code")) {
var code = parseInt(res.code);
if (code === 200) {
console.log("success fileUpload===>", res);
if (fileIndex + 1 === fileCountTotal) {
_this.setUploadPercent(uploadPercentProgress, 100);
_this.handleMerge.call(_this);
console.log("关闭进度条");
}
resolve();
} else {
reject("文件上传失败" + fileIndex);
}
} else {
reject("文件上传失败" + fileIndex);
}
}, function (error) {
console.log("error fileUpload===>", error);
reject("文件上传失败" + fileIndex);
})
})
},
handleMerge: function() { // 发起合并...},
handleUpload: function() {
this.creatModelTask()
.then(this.createQueueArr)
.then(this.handleQueueArr)
.catch(function(error) {
cosole.log(error);
})
},
listenerAddFile: function(e) { // input框选择文件监听
...
this.handleUpload();
},
bindEvents: function() {
// 选择文件确定后,立即处理上传
this.DOM.uploadModelInputFile.addEventListener("change", this.listenerAddFile.bind(this));
},
init: function() {
this.bindEvents();
}
}
var uploadModel = new UploadModel();
uploadModel.init(); |
|