Javascript - XMLHttpRequest 如何同时发送多个请求?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7595206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 00:38:41  来源:igfitidea点击:

Javascript - XMLHttpRequest how to send multiple simultaneous requests?

javascriptajaxtomcatxmlhttprequest

提问by deadCrow

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:

我遇到了一个非常超自然的问题。我正在尝试实现一个购物车,我在客户端存储了 cookie,以识别订购了哪些商品的 ID 及其数量。当我加载结帐 HTML 页面时,我正在读取 cookie 并一个接一个地获取项目 ID;然后对于每个项目 ID,我将向我的 servlet 发送请求,该 servlet 将返回信息。我截断了多余的行以使其易于遵循:

 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..

如果我将请求类型更改为同步通信,即从 TRUE 到 FALSE,则一切正常,但正如您所知,网页将不得不等待服务器处理每个项目。因此,网页将发送对项目 84234 的请求,等待,当有响应时,然后发送对项目 84239 的请求,等等。

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.

据我所知,如果我改回 ASYNCHRONOUS XMLHttpRequest,除了/仅当 arrXhr[ItemToProcess].readyState==1 时什么都不会发生。但是对于其他状态,2,3,4(4 是最重要的开始工作),它们永远不会被触发。

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.

知道为什么吗?最重要的是,我们如何才能克服这一点?我知道 XMLHttpRequest 在一个单独的线程上工作,很可能这就是问题所在,但我想不出解决方案。

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 ;)

我的目标很简单,我希望我的网页在从磁盘上的 cookie 读取时立即向我的 servlet 发送多个请求;因此,对于每个 cookie,我想发送一个请求并期望以异步方式接收响应。我不希望浏览器一直等待直到最终请求完成。所以,如果你有任何其他想法/实现,我可以是一个非常开放的人;)

p.s. I'm using TomCat 7

ps 我使用的是 TomCat 7

回答by Andrew D.

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
     }
   }
 }

回答by Emmanuel Chiarello

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

你必须使用“this”而不是 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
        }  
   }

回答by Mikolas Pansky

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.

请注意,由于对用户体验的负面影响,Gecko 30.0(Firefox 30.0 等)弃用了同步请求。

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.

到目前为止,onreadystatechange 可能会带来很多并发症和头痛。当您处理多个响应并且响应处理的顺序很重要时,这一点尤其正确。

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

当您想在响应到达时对其进行处理时,有一种简单的方法可以将 EventListener 添加到每个请求中。

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);

回答by Vlad Balmos

instead of sending multiple simultanous requests for each product id, wrap all the ids into an array, serialize it and use only one request.

不是为每个产品 id 同时发送多个请求,而是将所有 id 包装到一个数组中,将其序列化并仅使用一个请求。

var ids = [1, 2, 3];
var serializedIds = ids.join('|'); // serializedIds = '1|2|3';

send only the serializedIds variable through the request

通过请求仅发送 serializedIds 变量