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

发布于 2024-12-07 04:24:15 字数 1801 浏览 0 评论 0原文

我遇到了一个非常超自然的问题。我正在尝试实现一个购物车,其中我在客户端存储了 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
             }  
       }

这里的问题是在线

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

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

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

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

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

ps我正在使用 TomCat 7

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

南街九尾狐 2024-12-14 04:24:15

接下来的事情:

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

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
     }
   }
 }
流星番茄 2024-12-14 04:24:15

如果您愿意使用异步处理,我强烈建议使用事件侦听器。

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

这(理解事件监听器)当然是异步的,并在响应到达后立即对其进行处理。

到目前为止,onreadystate 的改变可能会带来很多并发症和头痛。当您处理多个响应并且响应处理的顺序很重要时,尤其如此。

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

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

...

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

...您甚至可以自定义您要处理的状态。这些是当前允许的响应状态:

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

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);
琴流音 2024-12-14 04:24:15

您必须使用“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
        }  
   }

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
        }  
   }
黎夕旧梦 2024-12-14 04:24:15

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

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

通过请求仅发送serializedIds变量

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

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

send only the serializedIds variable through the request

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文