【问题标题】:Javascript - XMLHttpRequest how to send multiple simultaneous requests?Javascript - XMLHttpRequest 如何同时发送多个请求?
【发布时间】:2011-09-29 09:27:27
【问题描述】:

我遇到了一个非常超自然的问题。我正在尝试实现一个购物车,我将 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);  

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

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

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

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

附言我正在使用 TomCat 7

【问题讨论】:

  • 只是评论:为什么不单独发送所有订购商品的请求?

标签: javascript ajax tomcat xmlhttprequest


【解决方案1】:

类似下一个:

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

【讨论】:

  • 问题:下面你做的代码重要吗? arrXhr[i].send(/*一些item数据发送到服务器,用于id为itemId的item*/);我的意思是send()中的参数,有什么用?他们会帮助解决这个问题吗?
  • 上面的代码是一个简单的例子,如何使多个异步请求为一个。使用异步模式时代码中的主要问题:.onreadystatechange= ProcessSrvRsp(intIcint)- 这一行没有任何意义。 .onreadystatechange=FunctionObject; 必须放在.send 之前。 .send(null)不向服务器发送任何数据?
  • 您可以通过更改代码进行一些改进:.onreadystatechange=ProcessSrvRsp.bind(window,intIcint); 如果不支持.bind(在 IE 中)查找Function.bind 兼容性。
  • 存在一些实现多个请求的方法。您可以使用一个变量,但在不同的闭包中创建多个 xhr。您可以使用 xhr 对象的数组。这不重要。但是你不能对所有请求单独使用 xhr
【解决方案2】:

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

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

这(了解事件监听器)当然是异步的,并在响应到达时立即处理。

到目前为止,onreadystatechange 可能会带来很多麻烦和麻烦。当您处理多个响应并且响应处理的顺序很重要时,尤其如此。

当您想要在响应到达时对其进行处理时,有一种简单的方法可以将 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);

【讨论】:

    【解决方案3】:

    你必须使用 "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
            }  
       }
    

    【讨论】:

      【解决方案4】:

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

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

      仅通过请求发送 serializedIds 变量

      【讨论】:

      • 嗨弗拉德,我不确定你的意思。但我怀疑您希望我汇总请求并将它们作为一个发送。问题是远程服务器可能需要很长时间来处理 50 或 150 个项目并将它们作为一个块发送回来。此外,我不确定 HTTP 或 Servlet 是否有限制,作为对客户端请求的响应的一部分,它被限制为向客户端抽出多少数据。话虽如此,如果只有 3 个同时请求,您的建议将是理想的。但是想象一下,如果我们有 100 个要查询的项目......
      • 在 50 或 150 个块中处理 50 或 150 个项目会慢得多。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      • 2014-09-18
      • 2019-05-15
      • 1970-01-01
      相关资源
      最近更新 更多