Warm tip: This article is reproduced from stackoverflow.com, please click
html jquery

Unable to wait for multiple AJAX calls to finish

发布于 2020-03-27 10:24:27

I am trying to send files to my API and want to do it one by one when multiple files are selected and use two different Post calls

In click event I get the files and loop through them then pass the file data to First() function call to get back the Unique Id (VersionID) and pass that VersionID when making the second call to second() function.

HTML

 <div class="progress">
        <div class="progress-bar">0%</div>
    </div>    
    <div id="status"></div>

JQuery

$(function () {
            var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;               
            var status = $('#status');
            $('#btnUploadFile').on('click', function () {
                $("#btnUploadFile").attr("disabled", true);
                var files = $("#fileUpload").get(0).files;
                var input = document.getElementById('fileUpload');
                for (var i = 0; i < input.files.length; ++i) {
                    var file = input.files[i];
                    first(9, file.name, (file.size / 1000), file.name.split('.')[1], function (versionID) {
                        $.when(second(versionID, files[i])).done(function(){
                            status.html('Uploading ' + i + ' of ' + input.files.length)});                        
                    });
                };
            });
        });

First Call

function first(libid, filename, filesize, fileextension, callback) {
            var form = new FormData();
            form.append("LibId", libid);
            form.append("FileName", filename);
            form.append("FileSize", filesize);
            form.append("FileExtension", fileextension);
            var settings = {
                "async": false,
                "crossDomain": true,
                "url": "URL",
                "method": "POST",                  
                "processData": false,
                "contentType": false,
                "mimeType": "multipart/form-data",
                "data": form
            }
            $.ajax(settings).done(function (response) {
                callback(response);
            });
        };

Second call

function second(versionId, fileData) {
            var data = new FormData();
            data.append('UploadedFiles', fileData);
            var bar = $('.progress-bar');
            var percent = $('.progress-bar');            
            $.ajax({
                async: true,
                crossDomain: true,
                url: "URL" + Math.floor(versionId).toString(),
                method: "POST",
                processData: false,
                contentType: false,
                mimeType: "multipart/form-data",
                data: data,                    
                xhr: function () {
                    var xhr = $.ajaxSettings.xhr();
                    xhr.onprogress = function e() {
                        // For downloads
                        if (e.lengthComputable) {
                            console.log(e.loaded / e.total);
                        }
                    };
                    xhr.upload.onprogress = function (e) {
                        // For uploads
                        if (e.lengthComputable) {                            
                            var percentVal = parseInt((e.loaded / e.total * 100), 10);
                            console.log("Loaded " + parseInt((e.loaded / e.total * 100), 10) + "%");
                            var percentValue = percentVal + '%';
                            bar.width(percentValue);
                            percent.html(percentValue);                            
                        }
                    };
                    return xhr;
                }
            }).done(function (response) {                
                percent.html("Completed");                 
            }).fail(function (e) {
                console.log("failed");
            });
        };

The issue is $.when(second(versionID, files[i])).done.... does not seem to wait before continuing the loop.

Current Behaviour:

It waits for the First() function to finish and then triggers Sencond() function but does not wait for Second() function before starting the new First() function.

Expected Behaviour

Wait for the First() function to fully finish and then wait for the Second() function to fully complete also before looping back to next file and call First() function again.

The other thing I am using async: false in First() function and async: true in Second() function as if I don't use async: true in Second() function, I cant get file upload progress.

Is it possible to wait for second() function to finish before continuing the loop while using AJAX async: true?

Questioner
Ali
Viewed
93
Quentin 2019-07-03 22:47

You have two problems.

First, when needs to be passed one or more thenable objects, but you are passing undefined. second has no return statement. There's no point in using when though, because you aren't running multiple functions in parallel.

The second problem is that while when won't call the done callback until everything you pass to it is done … the for loop will not wait for the when to complete.


There are two approaches you can do to solve this problem:

  1. Remove the for loop
    • Keep var i
    • Have first increment i
    • Call first recursively from second (until i is input.files.length)
  2. Use async / await to manage the promises returned from $.ajax (which will let you keep the loop).

The latter approach will require the use of a transpiler like Babel if you want to support older browsers.