Javascript - XMLHttpRequest how to send multiple simultaneous requests?

20,458

Solution 1

Something like next:

function ProcessCheckout() {
    var arrXhr=[];
    var myArr=[];
    myArr.push(84234);
    myArr.push(84239);
    myArr.push(84240);

    var helperFunc=function(arrIndex,itemId) {
      return function() {
        if(arrXhr[arrIndex].readyState===4) {
          //doing some functionality here on item
          ProcessResponseForItem(arrIndex,myArr,arrXhr);
          // doing some code if all xhr's is completed
          ProcessResponseForAllItems(myArr,arrXhr);
        }
      }
    }

    for(var i=0; i<myArr.length; i++) {
      var itemId=myArr[i]; 
      arrXhr[i]=new XMLHttpRequest();
      arrXhr[i].open('POST', strRemoteUriReq, true);
      arrXhr[i].onreadystatechange=helperFunc(i,itemId);
      arrXhr[i].send(/*some item data sended to server for item with id itemId*/);
    }
 }

 function ProcessResponseForItem(arrIndex,myArr,arrXhr) {
   if(arrXhr[arrIndex].status===200) {
     // do some code if response is succ
   }
   else {
     // if fail
   }
 }

 function ProcessResponseForAllItems(myArr,arrXhr) {
   var i,isAllComplete=true,isAllCompleteSucc=true;
   for(i=0;i<myArr.length;i++) if((!arrXhr[i])||(arrXhr[i].readyState!==4)) {
     isAllComplete=false;
     break;
   }
   if(isAllComplete) {
     for(i=0;i<myArr.length;i++) if(arrXhr[i].readyState!==200) {
       isAllCompleteSucc=false;
       break;
     }
     if(isAllCompleteSucc) {
       // do some code when all is completed and all is succ
     }
     else {
       // do some code when all is completed and some is fail
     }
   }
 }

Solution 2

I'd strongly suggest using the Event Listeners in case You're willing to use asynchronous processing.

Note that Gecko 30.0 (Firefox 30.0 etc.) deprecated the synchronous requests due to negative impact on user's experience.

This (understand Event Listener) is of course asynchronous and processes the responses as soon as it arrives.

So far the onreadystatechange could bring a lot of complications and headaches. This is especially true when You're handling more than one responses and the order of the response processing matters.

When You want to process the responses as it arrives there is a simple way to add EventListener to each of the requests.

arrXhr[intIcint].open('POST', strRemoteUriReq, true);                         
arrXhr[intIcint].addEventListener("load", processResponse);
arrXhr[intIcint].send(null);                                       

...

function processResponse() {
  console.log("Response arrived.");
}

... You can even customize the state You're going to process. These are the currently allowed states of response:

arrXhr[intIcint].addEventListener("progress", updateProgress);
arrXhr[intIcint].addEventListener("load", transferComplete);
arrXhr[intIcint].addEventListener("error", transferFailed);
arrXhr[intIcint].addEventListener("abort", transferCanceled);

Solution 3

You have to use "this" instead arrXhr[intIcint]

var arrXhr = new Array();
 function ProcessCheckout(){
    try
        {
            var myArr = new Array();
            myArr[0]=84234;
            myArr[1]=84239;
            myArr[2]=84240;

            for (var intLoop=0; intLoop < myArr.length; intLoop++){
                var intIcint=myArr[intLoop]; 

                xhr= new XMLHttpRequest();
                function Populate_CheckOutCart(){
                xhr.open('POST', strRemoteUriReq, true);                         
                xhr.send(null);                                       
                xhr.onreadystatechange= ProcessSrvRsp();
                // or   xhr.addEventListener("load", ProcessSrvRsp);

            }
        }catch(errors)
           {
              alert(errors.message);
           }
     }
 }

    function ProcessSrvRsp(){
        if (this.readyState==4){   
            //doing some functionality here on item code: this
        }  
   }
Share:
20,458

Related videos on Youtube

deadCrow
Author by

deadCrow

Updated on July 26, 2020

Comments

  • deadCrow
    deadCrow almost 4 years

    I'm encountering a very paranormal problem. I'm trying to implement a shopping cart, whereby I have cookies stored on the client side to identify which items' ID have been ordered and their quantities. When I load the checkout HTML page, I'm reading the cookies and getting the item id one after the other; then for each item id I ll be sending the request to my servlet which would return the information. I have truncated redundant lines to keep it simple to follow:

     var arrXhr = new Array();
     function ProcessCheckout(){
            try
            {
                var myArr = new Array();
                myArr[0]=84234;
                myArr[1]=84239;
                myArr[2]=84240;
    
                for (var intLoop=0; intLoop < myArr.length; intLoop++){
                    var intIcint=myArr[intLoop]; 
    
                    arrXhr[intIcint]= new XMLHttpRequest();
                    function Populate_CheckOutCart(){
                    arrXhr[intIcint].open('POST', strRemoteUriReq, true);                         
                    arrXhr[intIcint].send(null);                                       
                    arrXhr[intIcint].onreadystatechange= ProcessSrvRsp(intIcint);
                }
            }catch(errors)
               {
                  alert(errors.message);
               }
         }
     }
    
           function ProcessSrvRsp(ItemToProcess){
                if (arrXhr[ItemToProcess].readyState==4){   
                    //doing some functionality here on item code: ItemToProcess
                 }  
           }
    

    The problem here is in line

    arrXhr[intIcint].open('POST', strRemoteUriReq, true);  
    

    If I change the request type to SYNCHRONOUS communication, i.e. from TRUE to FALSE, everything works correctly, but as you know the web page will have to wait for the server to process every item. Hence, the web page will send a request for item 84234, waits, when there is a response then sends a request for item 84239, etc..

    From my knowledge, if I change back ASYNCHRONOUS XMLHttpRequest, nothing happens except/only when arrXhr[ItemToProcess].readyState==1. But as regards the other states, 2,3,4 (4 being the most important to start working with), they are never triggered.

    Any idea why? And most importantly how can we overcome this? I'm aware that the XMLHttpRequest works on a separate thread and most probably this is the issue, but I can't figure out a solution.

    My objective is simple, I want my web page to send multiple requests to my servlet simultaneously as soon as it is reading from the cookies on the disk; hence for each cookie I want to send a request and expect to receive a response in an asynchronous way. I don't want the browser stuck waiting until the final request has been completed. So, if you have any other idea/implementation, I can be a very open minded person ;)

    p.s. I'm using TomCat 7

    • Andrew D.
      Andrew D. over 12 years
      Just a comment: why do not send alone request for all ordered items?
  • deadCrow
    deadCrow over 12 years
    Question: Is the code below you have done important? arrXhr[i].send(/*some item data sended to server for item with id itemId*/); I mean the parameters in the send(), what are the use? will they help to solve this issue?
  • Andrew D.
    Andrew D. over 12 years
    Code above is a simple example how to make mulitple async request as one. Main problem in your code when used async mode: .onreadystatechange= ProcessSrvRsp(intIcint)- this line no any sense. .onreadystatechange=FunctionObject; must be placed before .send. .send(null) no send any data to server?
  • Andrew D.
    Andrew D. over 12 years
    You can make some improvements by changing in your code: .onreadystatechange=ProcessSrvRsp.bind(window,intIcint); If .bind is not supported (in IE) lookup for Function.bind compatibility.
  • deadCrow
    deadCrow over 12 years
    Andrew, you're brilliant it worked as you have described in your first post! I'm so in debt!! I think that all boiled down as in your code where you have typed var helperFunc=function(arrIndex,itemId) { return function() { ... } problem is I don't know why that worked.. you have assigned a function to a variable and you are returning another function, whereby in the latter function it is not returning anything but still it worked. Why's that??
  • Andrew D.
    Andrew D. over 12 years
    1) .onreadystatechange is needed to set an function pointer (e.g. function xxx(){}; xhr.onreadystatechange=xxx; 2) second problem that you need to send into function xxx parameters with preserved value; 3) my helperFunc resolve this problems: helperFunc gets as parameters some values to preserve in closure, create new function, that can see preserved parameters, and return this new function to store into .readystatechange
  • Andrew D.
    Andrew D. over 12 years
  • deadCrow
    deadCrow over 12 years
    I will definitely go into them since I have never met this "closure problem" before.. but it does make a lot of sense! one last question: I have tried to remove the array of XMLHttpRequest as I believe that I was creating arrays of requests a bad idea. Instead I made a single variable of this type; however it gave a problem Error arrXhr.status == 0 instead of the expected arrXhr.status ==200. Most probably because I tried to use a single class-instance of the XMLHttpRequest instead of multiple ones. What's your opinion Andrew?
  • Andrew D.
    Andrew D. over 12 years
    Exists some count of ways to implement multiple request. You can use one variable but create multiple xhr's in different closures. You can use array of xhr's objects. This not important. But you cannot use alone xhr for all requests
  • deadCrow
    deadCrow over 12 years
    Thanks Andrew. To answer your question because I have just seen it now. I m not sending one request (containing all the others items in an array or something) because the remote server would take longer to process such many request and would give the webclient the impression that it stalled. Further to that it gives the client the impression that it is doing something and is seeing things being populated on his checkout. I'm in no way arguing that it is not a good idea either. But at some point or another I would have had a similar problem now thanks to you it is solved!
  • deadCrow
    deadCrow over 12 years
    Hi Vlad, I'm not sure what you mean by that. but i'm suspecting you want me to aggregate the requests and send them as one. The problem is that the remote server might take long to process 50 or 150 items and send them back as one chunk. Also I'm not sure if HTTP or the Servlet has a limit on how much data it is limited to pump down to the client as part of its response to the client request. Having said that, if there were only 3 simultaneous request your suggestion would be ideal. however imagine if we had 100 items we are querying for...
  • Stephan Bijzitter
    Stephan Bijzitter about 9 years
    It will be much slower processing 50 or 150 items in 50 or 150 chunks.

Related