Project background

In a small company, the company from somewhere else to buy a 20 years old old JSP project (drunk), after seven or eight generations of hands, there is only more chaos, not the most chaos, only you can not imagine the chaos. There is no Babel, there is no Webpack, there is only iframe+jQuery+ Tomcat + Eclipse. Despair…

Fragment upload core code

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);
Copy the code

Handling of broken affairs before and after uploading (combined with business)

Background file reception, can only be synchronous form, asynchronous merge file error, speechless… In the spirit of optimization, let’s make a queue for uploading slices. The key parameter is the index of slices, and the background merges files according to the index of slices

  1. File type detection
  2. File size detection (I asked the product for a limit, but the product said no, and after my repeated requests, they gave 10G…)
  3. Parsing zip file subfiles (FileReader processing, not the key of this article, not to go into detail)
  4. Obtaining the MD5 value of the file (github.com/satazor/js-…)
  5. Create upload task (get TasKID) – creatModelTask
  6. Generate upload task queue – createQueueArr
  7. Process queue, fragment upload – handleQueueArr+fileUpload
  8. After uploading, initiate file merge request – handleMerge

upload

function UploadModel() {
    this.DOM = {
        uploadModelInputFile: document.querySelector("#uploadModelInputFile"UploadConfig = {maxFileSize: 10 * 1024 * 1024 * 1024, acceptFileTypes: ["zip"."rvt"."dwg"} this.uploadModelargs = {fileBlob: null, // Select file modelName: // file name md5: null, // file md5 fileSuffix: null, // fileSuffix (dotted) fileCountTotal: null, // total number of blocks taskId: } this. API = {modelUpload_upload:function(formData) {// Uploadreturn $.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// Do not process data contentType:false, // do not set content type}); } } UploadModel.prototype = { creatModelTask:function() {// Create upload task},setUploadPercent: function(fileIndex, fileCountTotal) {// Set the upload progress bar var percent = math.ceil (fileIndex/fileCountTotal * 100); percent = percent > 100 ? 100 : percent; console.log("Upload progress ==>", 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 = []; // Upload the task queuewhile(start < fileSize) { var fd = new FormData(); var chunk = _this.uploadModelArgs.fileBlob.slice(start, end); // Cut 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) {/ / processing task queue / / https://github.com/mqyqingfeng/Blog/issues/90
        if(array.isarray (queueArr) &&queuearr. Length > 0) {// Create iterator protocol (non-iterable protocol) 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(); / / recursion},function (error) {
                    console.log(error);
                    console.log("File upload failed. Please try again.") }) } } } exectorIterator(); }, /** * Slice upload * @param {FormData} fd Upload parameter * @param {Number} fileIndex Current slice index * @param {Number} fileCountTotal Number of slices * @param {Element} uploadPercentProgressfunction (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("Close the progress bar");
                  }
    
                  resolve();
                } else {
                  reject("File upload failed"+ fileIndex); }}else {
                reject("File upload failed"+ fileIndex); }},function (error) {
              console.log("error fileUpload===>", error);
              reject("File upload failed" + fileIndex);
            })
    })
  },
  handleMerge: function() {// initiate a merge... }, handleUpload:function() {
      this.creatModelTask()
        .then(this.createQueueArr)
        .then(this.handleQueueArr)
        .catch(function(error) {
            cosole.log(error);
        })
        
  },
  listenerAddFile: function(e) {// Input box select file listener... this.handleUpload(); },bindEvents: function() {/ / select files immediately after the treatment to upload this. DOM. UploadModelInputFile. AddEventListener ("change", this.listenerAddFile.bind(this));
  },
  init: function() {
      this.bindEvents();
  }
}

var uploadModel = new UploadModel();
uploadModel.init();
Copy the code

How does the extension implement breakpoint continuation

Thinking of XHR’s abort method to cancel sending requests, handleQueueArr needs to be modified (manually funny);

In addition, if the file has been uploaded, the server needs to cooperate next time (the MD5 value of the file above determines whether the file has been uploaded).

Write in the back

There are still many loopholes and optimizations in the code, which need to be improved. If there are mistakes, please point them out.

The resources

【ES6 Basics 】 Iterators

js-spark-md5

FileReader

Thoroughly understand the operation of files and binary data

Blob objects · Issue #10

Why is the video link address of video website blob?

Js compressed file reading processing