-1

I have a web page that, when submitted, adds an unlimited number of items to our database. To avoid time outs due to too many items being submitted, I'd like to use jQuery and AJAX calls to a web service instead.

I'm trying to figure out how to write my loop that makes these AJAX calls so that it A) allows for multi-threading and B) won't hang the browser.

A simple look might look this this:

elementsToProcess.each(function() {
    // TODO: Submit AJAX call for this element
});

But does this hang the browser, and does it allow for multi-threading?

Thanks for any tips.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Where do you want/need to avoid the timeout? In the database responding? From making (too) many parallel ajax requests? – Bergi Aug 25 '14 at 16:49
  • 1
    From your loop, could you create an object or array (or something) and then send THAT object to your service? Your service could interrupt the data & respond accordingly. – Damon Aug 25 '14 at 16:50
  • What are you doing in that loop, do you really want one ajax call per element? What is `elementsToProcess`, is that the array with the items that has unlimited length? – Bergi Aug 25 '14 at 16:51
  • Check this http://stackoverflow.com/questions/25220486/xmlhttprequest-in-for-loop/25220766#25220766 or this http://stackoverflow.com/questions/24773307/sending-post-request-in-for-loop/24774532#24774532 and this – hex494D49 Aug 25 '14 at 16:52
  • @Bergi: I get a timeout if I don't use AJAX calls and simply post the entire page and process everything at one. I'm looking at AJAX as a better solution. – Jonathan Wood Aug 25 '14 at 16:55
  • @dragonslovetacos: I fear that approach would produce a timeout as the number of items could be a thousand or more. For that reason, I think I need to avoid processing everything at once. – Jonathan Wood Aug 25 '14 at 16:56
  • @Bergi: The only thing I'm doing in the loop is getting the data I need from the current element in order to submit the AJAX call. – Jonathan Wood Aug 25 '14 at 16:56
  • @JonathanWood: Then avoid the timeout by making the calls to the database asynchronous, and immediately return a "now processing the items" response from the server (and then repeatedly reload/check via ajax whether the processing is done). This problem is not solved by making multiple ("unlimited") requests from client to server. – Bergi Aug 25 '14 at 16:58
  • @Bergi: I'm not sure exactly how that would work. Making multiple requests from the client to the server would solve the problem because each request would be short. But I'm certainly open to considering a better approach. Do you know of any examples? – Jonathan Wood Aug 25 '14 at 17:00
  • @JonathanWood: Making a request from client to server for each item only eats up bandwith to your server connection, and slows down the whole process - there are still N database updates to be done. You need to find a way to speed up the N server->database requests, or make them asynchronous, so that you can send the server->client response *earlier* (instead of more often). – Bergi Aug 25 '14 at 17:03
  • @Bergi: I know my approach will take longer overall, but it will prevent time outs. As indicated, I'm open to a better way, but I'm sorry, I'm not getting a good picture of an alternative approach from your description. As indicated in my question, I think it should be asynchronous. But that's where I'm getting hung up. – Jonathan Wood Aug 25 '14 at 17:06
  • @Bergi: Also, it probably makes sense to do 50 or so with each AJAX call rather than just one at a time. Anyway, looks like you've finished here. – Jonathan Wood Aug 25 '14 at 17:13
  • Sorry for bothering again, but have you checked the links I posted above? I believe the first one provides a solution to your question; In general, use asynchronous calls, each of them will have its one _route_; group them if you think you're requsting too often and you'll be fine. If you dont undestand the code there, let me know and I'll explain it in details. – hex494D49 Aug 25 '14 at 17:19
  • @hex494D49: Sorry, I did follow the link and I didn't understand it. Looking at the solution for the first question, I see a loop that makes AJAX calls. It uses a simple `for` loop, which isn't multi-tasking. I'm also trying to figure out how I would know when these AJAX calls have all completed. – Jonathan Wood Aug 25 '14 at 17:28
  • This line `if (xhr[i].readyState == 4 && xhr[i].status == 200) {` there, or in other words, this condition tells you that the request `i` is successfully over. Instead of using a loop, you may have an event which will trigger an Ajax call. – hex494D49 Aug 25 '14 at 17:37
  • @hex494D49: Thanks. As you can see, JavaScript is not my main area of expertise. So I'm understanding that the `for` loop is not multi-threading, but the calls being made from that loop are asynchronous so it doesn't really matter. I think I agree this is the basic approach I need. As far as knowing when the calls are done, I'd prefer to just use `$.post()` so I don't plan to have a `XMLHttpRequest` object around. Perhaps I should post another question for that. – Jonathan Wood Aug 25 '14 at 17:42

1 Answers1

1

I believe this example demonstrates what your asking:

var filesSelected = document.getElementById("privateDocs").files;

var progressholders = document.getElementsByClassName("progressholders");

for(var i=0; i<filesSelected.length; i++) {

    var p = document.createElement("progress");
        p.value = "0";
        p.max = "100";

    var t = document.createElement("span");

    progressholders[i].innerHTML = "";  
    progressholders[i].appendChild(p);
    progressholders[i].appendChild(t);          

    var formData = new FormData();
        formData.append('file', filesSelected[i], filesSelected[i].name);

    UploadDocToServer("upload.php", formData, p, t);                    
}       

the actual ajax function

function UploadDocToServer (formUrl, formData, progressBar, totalBar) {
  var parent = progressBar.parentNode;

  var ajaxRequest = new XMLHttpRequest();
    ajaxRequest.upload.addEventListener("progress", function(event) {
            totalBar.innerHTML = event.loaded + "bytes of " + event.total + "bytes";
            var percent = (event.loaded / event.total) * 100;
            progressBar.value = Math.round(percent);

        }, false);
    ajaxRequest.addEventListener("load", function(event) {
        progressBar.parentNode.removeChild(progressBar);

        var info = document.createElement("span");
        info.innerHTML = event.target.responseText
        parent.appendChild(info);

    }, false);

    ajaxRequest.addEventListener("error", function() {
        progressBar.parentNode.removeChild(progressBar);

        var info = document.createElement("span");
            info.innerHTML = "Erorr Uploading.";

        parent.appendChild(info);
    }, false);

    ajaxRequest.addEventListener("abort", function() {
        progressBar.parentNode.removeChild(progressBar);

        var info = document.createElement("span");
            info.innerHTML = "Abort called.";

        parent.appendChild(info);
    }, false);

ajaxRequest.open("POST", formUrl);
ajaxRequest.send(formData);

}
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
shuskic
  • 81
  • 2
  • Aren't progress events for uploads? – Bergi Aug 25 '14 at 17:04
  • Thanks, but I'm not sure I understand this. Any chance you could provide a bit more detail about what `UploadDocToServer` is doing? Also, I notice you use a regular `for` loop instead of `each()`. Doesn't that tie up the UI a bit more? – Jonathan Wood Aug 25 '14 at 17:08
  • Jonathan, If you want multi-threading; just create a function(UploadDocToServer) that creates the ajax request and use it in your each loop. Javascript is anonymous; it will not wait until the function to finished by default. So you will have multiple ajax requests at once(multi-threading). – shuskic Aug 25 '14 at 17:12
  • Thanks. Is there a way to know when all the threads are done? – Jonathan Wood Aug 25 '14 at 17:14
  • I believe so. You could create an array before the each loop. Once the ajax request is done; you can push a value to that array. Then you could create a while loop; once the length of the array is equal to the number of ajax requests your sending; all is done!. But I would process the response from the server one by one. – shuskic Aug 25 '14 at 17:18