locked
Can't we use WinJS.xhr in a for loop???

    Question

  • HI,

    I want to call a url for 30 times and I used WinJS.xhr  in a loop to make it iterate for 30 times but I am unable to get the response....can I use WinJs.xhr in loops?..pls help me..  

    Thursday, July 05, 2012 5:56 PM

Answers

  • This was the code I tried.....
                                        for (var i = 0; i < Ids.length; i++)
                                      {
                                            FromId[i] = data[i].id;;
                                            WinJS.xhr({ type: 'GET', url:"https://www.xyz.com/"+FromId[i] }).done(function (res) {

                                                sampleArray[i] = JSON.parse(res.responseText);

                                            });
                                           }

    If I use the below code outside the loop I was able see the response in res

     WinJS.xhr({ type: 'GET', url:"https://www.xyz.com/"+FromId[i] }).done(function (res) {
                                               
                                                sampleArray[i] = JSON.parse(res.responseText);
                                               
                                            });

                                                                                           
    • Marked as answer by sandbha Wednesday, September 26, 2012 9:41 PM
    Friday, July 06, 2012 9:24 AM
  • Keep in mind that a call to xhr is asynchronous.  By the time the done function is executed, the for loop will have moved to the next items in the list variable i will not be what you are expecting. Try pushing your results onto the sample array instead of setting the value by index.

    sampleArray.push(JSON.parse(res.responseText));


    Dave Paquette @Dave_Paquette www.davepaquette.com


    Friday, July 06, 2012 2:00 PM
  • It works fine in a loop!

     var sampleArray = new Array();

        function btnClick(event) {

           

            for (var i = 0; i < 3; i++) {

                WinJS.xhr({ url: "http://www.microsoft.com" }).done(
                    function fulfilled(result) {
                        if (result.status === 200) {
                            sampleArray.push(result.statusText);
                        }
                        else {
                           
                        }
                    });
            }
        }

        app.onactivated = function (args) {
            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension.
                    // Restore application state here.
                }
                args.setPromise(WinJS.UI.processAll());
                document.getElementById("btnPush").addEventListener("click", btnClick);
            }
        };



    Jeff Sanders (MSFT)



    Monday, July 09, 2012 7:16 PM
    Moderator

All replies

  • Can you provide a code sample?  Does your code work if the call is made outside a loop?

    Dave Paquette @Dave_Paquette www.davepaquette.com

    Thursday, July 05, 2012 7:05 PM
  • This was the code I tried.....
                                        for (var i = 0; i < Ids.length; i++)
                                      {
                                            FromId[i] = data[i].id;;
                                            WinJS.xhr({ type: 'GET', url:"https://www.xyz.com/"+FromId[i] }).done(function (res) {

                                                sampleArray[i] = JSON.parse(res.responseText);

                                            });
                                           }

    If I use the below code outside the loop I was able see the response in res

     WinJS.xhr({ type: 'GET', url:"https://www.xyz.com/"+FromId[i] }).done(function (res) {
                                               
                                                sampleArray[i] = JSON.parse(res.responseText);
                                               
                                            });

                                                                                           
    • Marked as answer by sandbha Wednesday, September 26, 2012 9:41 PM
    Friday, July 06, 2012 9:24 AM
  • Keep in mind that a call to xhr is asynchronous.  By the time the done function is executed, the for loop will have moved to the next items in the list variable i will not be what you are expecting. Try pushing your results onto the sample array instead of setting the value by index.

    sampleArray.push(JSON.parse(res.responseText));


    Dave Paquette @Dave_Paquette www.davepaquette.com


    Friday, July 06, 2012 2:00 PM
  • Dave is right   that "By the time the done function is executed, the for loop will have moved to the next items in the list variable i will not be what you are expecting."..Because those request are async.

    What you need to do is use closure.....

      for (var i = 0; i < Ids.length; i++) 
                                      {
    (function(i){
    
            FromId[i] = data[i].id;;
            
            WinJS.xhr({ type: 'GET', url:"https://www.xyz.com/"+FromId[i] }).done(function (res) {
                                                sampleArray[i] = JSON.parse(res.responseText);
    
                                            });
    
    })(i);
                                      }//Ends for look

    did you notice, your actual code is running inside a self executing anonymous function..!!

    Cheers...!


    • Edited by Web-Farmer Friday, July 06, 2012 5:47 PM variable named changed..
    Friday, July 06, 2012 5:46 PM
  • Thank you Dave for your reply..

        I tried the thing what you said but I was unable to get the response it was showing that response contains undefined...

    please let  me is there any alternative?

    Friday, July 06, 2012 7:42 PM
  • thank you Web-Farmer for your reply.

    I tried the code which you have given and I got the same message that response was undefined

    Friday, July 06, 2012 7:45 PM
  • You can debug this yourself.

    Open base.js and place a breakpoint in the appropriate calls.

    You will find XHR around line 2300 in that file!

    -Jeff


    Jeff Sanders (MSFT)

    Friday, July 06, 2012 8:34 PM
    Moderator
  • hi jeff sanders,

    whether xhr works fine in loop ?or not?please let me know...

    Monday, July 09, 2012 6:28 PM
  • It works fine in a loop!

     var sampleArray = new Array();

        function btnClick(event) {

           

            for (var i = 0; i < 3; i++) {

                WinJS.xhr({ url: "http://www.microsoft.com" }).done(
                    function fulfilled(result) {
                        if (result.status === 200) {
                            sampleArray.push(result.statusText);
                        }
                        else {
                           
                        }
                    });
            }
        }

        app.onactivated = function (args) {
            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension.
                    // Restore application state here.
                }
                args.setPromise(WinJS.UI.processAll());
                document.getElementById("btnPush").addEventListener("click", btnClick);
            }
        };



    Jeff Sanders (MSFT)



    Monday, July 09, 2012 7:16 PM
    Moderator
  • remove i in the closure , you will not get the undefined error, i tried using closure even then the xhr is called only for the last element in the loop
    Sunday, October 28, 2012 3:58 AM
  • hi,

     Is it possible to increment i and do the next iteration when the first xhr finishes?

    I currently use recursive function to iterate an async method.  But not sure if it is the right way. Is there a better way to do?

    function importdb(list) {
        db.insertAsync(list[list.length - 1]).done(function complete() {
            list.pop();
            if (list.length != 0) importdb(list);
        });
    }
    
    

    Friday, December 21, 2012 3:46 AM
  • hi,

     Is it possible to increment i and do the next iteration when the first xhr finishes?

    I currently use recursive function to iterate an async method.  But not sure if it is the right way. Is there a better way to do?

    function importdb(list) {
        db.insertAsync(list[list.length - 1]).done(function complete() {
            list.pop();
            if (list.length != 0) importdb(list);
        });
    }

    If you are going to follow this pattern and order is important, than a recursing function would be ideal.  That said, I want to observe to all concerned that using XHR's this way is not ideal as it is very inefficient and resource heavy across your entire service chain.


    On the client side, each of these XHR's consume compute cycles during their complete lifecycle, and they also consume memory.  They are also inefficient from a transactional perspective because regardless of whether or not you run multiple requests concurrently or chain them (as above), they each entail latency introduced through the network itself and the complete transactional cycle.  Modern browsers (including IE10) cap the number of simultaneous requests.  The number can vary by platform, but 6 is a pretty common number.  I would not be at all surprised if the version of IE10 serving as the backbone for Metro apps limits further.  If you have 30 iterations to complete and he 'browser' can only handle 4 connections at a time, what happens is that the rest of the requests simply queue up and wait.  You then incur 30 / 4 times the single transaction latency for your complete set.  Multiply that across hundreds of requests and it can become very VERY painful.  It also leads to a poorly performing client side, because you are essentially maxing the applications communicative bandwidth.  The bottom line is this will make your application slow, and it will beat up on the user's resources and battery.


    From a network perspective, this pattern massively increases network traffic because you take each transaction for a datum and you force a lots of handshaking and maintenance packets across the network.  By artificially increasing the number of requests that need to be made, you really eat up network bandwidth, which not only increases the data burn of your app, it also reduces performance because it chains the speed at which the app can collect and handle information to the speed of the network, which is really bad in a transactional system.


    From a server side perspective, you are beating up on your systems from the web server all the way through to the DB.  Every XHR consumes server resources, demanding an open connection, a wait, and a callback.  In a large volume system, an architectural pattern like this can mean the difference between a system that works well, and one that is highly unstable and prone to failure.  At the very least, it increases cost.  Imagine, if you will, 30,000 users all hitting your web server 30 times within a few second period.  It is a very very large volume, and it creates serious scalability issues.


    Ok, so what that all leads me to is this: why aren't you doing this aggregation on the server, and returning your data set as one JSON object that you can parse on the client?  This is greatly more efficient.


    To the original poster, I want to point out that if you need to maintain order in your result set (and you have no alternative mechanism for establishing order), then calling the XHR's in a for loop is not advisable, because it will result in n XHR's executing simultaneously (however many the system can handle).  You will not be in control of the return order for them - that is, the callbacks for each will operate independently, and that can lead to return order and fire order discrepancies (e.g. fired first, but returned third).  So, if you had some data that you needed to get back in the same order that you called it, this method would be fragile.  You also, in code, will have to correct for the failure of individual XHR's, which means your code will need to be more complex in this approach than in a single server side aggregation call.  That is another drawback.


    So, I query this simply: why aren't you aggregating the data on the server and returning it as a single JSON object, accessed by a single AJAX call?


    • Edited by tt92618 Friday, December 21, 2012 6:31 AM
    Friday, December 21, 2012 6:28 AM
  • Hi,

    For me the order of result should be maintained as I am doing a series on indexeddb operations, not xhr.  My question was in the context of async operation in general. Perhaps I should have asked in a separate thread.  Looks like there is no alternate way than using recursive function if order is to be maintained. Thanks. 

    Saturday, December 22, 2012 3:32 PM