繁体   English   中英

基于延迟承诺的多文件上传处理,在 for 循环中使用 javascript 到使用 ajax 的 esp32

[英]Deferred promise based multiple file upload handling with javascript in a for loop to an esp32 with ajax

你好!

我想用 javascript/jquery 上传多个文件。

我的后端是 esp32。

当前代码仅适用于一个文件,但无法上传多个文件。 当数组中有多个文件时,它只上传一半的文件。

这是我的代码:

var promises = [];
//Gets called onchange
function dragAndDrop(el){
    promises = [];
    // Get all the files from the input element
    var files = $(el).prop('files');
    // Make sure there are files, but it's onchange so it must be.
    if(files){
        // add spinner icon to indicate the upload start to the user
        $("#uploadIndicatorIcon").html( '<i class="fas fa-spinner fa-spin"></i>' );
        // Check if the files fit in the filesystem
        if( !isFileArrFits(files) ){
            debug("error","There is not enough space for the files!");
            uploadingDone();
            return false;
        }
        // iterate trought all the files and upload them one by one.
        for (let file of files) {
            promises.push( uploadFile(file) );
        }
        // register the promises done from the ajax.
        updatePromises();
    }
}

function updatePromises(){
    $.when.apply(null, promises).done(function() {
        if(promises.length > 1){
            $('.file-input').prev().text("Files uploaded.");
            debug("success","Files uploaded.");
        }else{
            $('.file-input').prev().text("File uploaded.");
        }
        setTimeout(() => {uploadingDone();}, 100);
    })
}

// reset everything
function uploadingDone(){
    $("#fileUploadInput").val("");
    $("#uploadIndicatorIcon").empty();
    $('.file-input').prev().text("or drag and drop multiple files or a firmware");
}

function uploadFile(file){
    var url = "/uploading";
    if( file.name.includes("firmware") ){url = "/uploadingfirm"}
    form = new FormData();
    form.append("file", file, file.name);
    return $.ajax({
        url: url,
        type: 'POST',
        data: form,
        processData: false,
        contentType: false,
        async: true
    }).done(function(resp){
        if( file.name.includes("firmware") ){
            debug("success","Firmware uploading success. The module is restarting...");
            setTimeout(() => {location.reload();}, 6500);
        }else{
            debug("success",`Uploaded: ${file.name}`);
        }
    }).fail(function(resp){
        debug("error",`Failed: ${file.name}`);
    });
}

我认为问题出在这里:

for (let file of files) {
  promises.push( uploadFile(file) );
}
updatePromises();

由于 esp32 无法在那样的时间内完成任务,我试图延迟这样的请求:

for (let file of files) {
  setTimeout(() => {
    promises.push( uploadFile(file) );
  }, 100); // tried also with 200,500 and 1000ms.
}
updatePromises();

我认为updatePromises()函数是问题所在,因为它在 promises 数组填满之前被调用。 所以我这样做了:

var filesIndex = 0;
for (let file of files) {
  setTimeout(() => {
    filesIndex++;
    promises.push( uploadFile(file) );
    if(filesIndex >= files.length){
       updatePromises();
    }
  }, 100); // tried also with 200,500 and 1000ms.
}

再次,没有成功。 这可能是因为文件在我注册承诺的回调之前就开始上传了。 有趣的是,在每种情况下都会调用 updatePromises 函数 get ,但文件总是只有一半。

如果我使用这种完全相同的方法只上传一个文件,则一切正常。

所以问题是。

如何延迟上传ajax? 我是否应该为每个文件分别设置一个变量以指示它是否已上传并上传下一个?

*编辑:这是已接受解决方案的工作代码:

function fileDragN_DropEvents(){
    var $fileInput = $('.file-input');
    var $droparea = $('.file-drop-area');
    $fileInput.on('dragenter focus click', function() {
      $droparea.addClass('is-active');
    });
    $fileInput.on('dragleave blur drop', function() {
      $droparea.removeClass('is-active');
    });
    $fileInput.on('change', function() {
      var filesCount = $(this)[0].files.length;
      var $textContainer = $(this).prev();
    
      if (filesCount === 1) {
        var fileName = $(this).val().split('\\').pop();
        $textContainer.text(fileName);
      } else {
        $textContainer.text(filesCount + ' files selected');
      }
    });
}

var promises = [];
function updatePromises() {
    $.when.apply(null, promises).done(function() {
        if(promises.length > 1){
            $('.file-input').prev().text("Files uploaded");
            debug("success","Files uploaded");
        }else{
            $('.file-input').prev().text("File uploaded");
        }
        setTimeout(() => {uploadingDone();}, 500);
    })
}

function uploadingDone(){
    $("#fileUploadInput").val("");
    $("#uploadIndicatorIcon").empty();
    $('.file-input').prev().text("or drag & drop multiple files or a firmware");
}

function dragAndDrop(el){
    promises = [];
    var files = $(el).prop('files');
    var promise = $.Deferred();
    promise.resolve();

    if( !isFileArrFits(files) ){
        debug("error","Files does not fit into the filesystem");
        uploadingDone();
        return false;
    }
    $("#uploadIndicatorIcon").html( '<i class="fas fa-spinner fa-spin"></i>' );

    for (let file of files) {
        promise = promise.then( () => uploadFile(file) );
        promises.push(promise);
    }
    updatePromises();
}

function uploadFile(file){
    var url = "/uploading";
    if( file.name.includes("firmware") ){url = "/uploadingfirm"}
    form = new FormData();
    form.append("file", file, file.name);
    return $.ajax({
        url: url,
        type: 'POST',
        data: form,
        processData: false,
        contentType: false,
        async: true
    }).done(function(resp){
        if( file.name.includes("firmware") ){
            debug("success","Firmware uploaded. Module restarts..");
            setTimeout(() => {location.reload();}, 6500);
        }else{
            debug("success",`Uploaded: ${file.name}`);
        }
    }).fail(function(resp){
        debug("error",`Failed: ${file.name}`);
    });
}

这是一个只使用$.Deferred

我个人从不使用$.Deffered ,但是,这是一个挑战,我想我遇到了

 // below this is just placehodler var files = [1, 2, 3, 4, 5]; function uploadFile(v) { var p = $.Deferred(); console.log(`${v} starting`); setTimeout(p.resolve, Math.random() * 1000 + 500, v); return p; } function updatePromises() { $.when.apply(null, promises).done(function() { console.log(arguments); }) } var promises = []; // above this is just placeholder // this is the change var promise = $.Deferred(); promise.resolve(); for (let file of files) { promise = promise.then(() => uploadFile(file) // not required, just shows sequence of events .then(r => { console.log(`${r} finished`); return `${r} done`; }) // end of unrequired code ); promises.push(promise); } // end of changes - the line below is the same as yours updatePromises()
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM