[ 
https://issues.apache.org/jira/browse/CB-4873?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14005959#comment-14005959
 ] 

Maris Seimanovs commented on CB-4873:
-------------------------------------

The problem is still relevant and can be reproduced on Windows Phone 8.1 (using 
emulator or real device with 8.1 developer preview) with a simple page with two 
sequential AJAX requests. Our team spent many hours trying to find what's going 
on and where our AJAX requests are messed up when we load multiple page parts 
through AJAX.

Here is a simplified code example to test.

index.html in application root:

{code:html}
    <!DOCTYPE html>
    <html>
        <head>
            <title>Mobile sandbox</title>
            <meta charset="UTF-8">
            <script type="text/javascript" 
src="libs/jquery/jquery.min.js"></script>
        </head>
        <body>
    
            <div id="redbox" 
style="width:100px;height:100px;background-color:red;">
            </div>
    
            <div id="greenbox" 
style="width:100px;height:100px;background-color:green;">
            </div>
             
            <script>
                $(function () {
    
                    alert("Requesting data for redbox...");
    
                    $.ajax("test/redText.html")
                      .done(function (text) {
                          alert("Filling redbox with contents " + text);
                          $("#redbox").html(text);
                      })
                      .fail(function () {
                          alert("Error in redbox");
                      })
                      .always(function () {
                          alert("Complete redbox");
                      });
    
                    alert("Requesting data for greenbox...");
    
                    $.ajax("test/greenText.html")
                      .done(function (text) {
                          alert("Filling greenbox with contents " + text);
                          $("#greenbox").html(text);
                      })
                      .fail(function () {
                          alert("Error in greenbox");
                      })
                      .always(function () {
                          alert("Complete greenbox");
                      });
    
                });
            </script>
        </body>
    </html>
{code}

test/greenText.html:
{code:html}
    <span>GREEN</span>
{code}
test/redText.html:
{code:html}
    <span>RED</span>
{code}

The only dependency to run this test is jQuery which I have put in libs/jquery/ 
folder.

When I deploy the same code to Windows Phone as Cordova app, the `redbox` 
request never receives any data, nor any errors. The `greenbox` request 
receives data of `redbox`, and thus we have empty red box and green box with 
text "RED" in it.
Here is the sequence of alerts:
{code}
    Requesting data for redbox...
    Requesting data for greenbox...
    Filling greenbox with contents <span>RED</span>
    Complete greenbox
{code}

I have no idea why it's the case - maybe Microsoft has changed something in 
Windows 8.1 and now the MiniBrowser_ScriptNotify calls are completely async. I 
know that WP 8.1 is not RTM yet but nevertheless I think the fix should be 
implemented anyway because it seems more safe and correct solution to have a 
separate callback function for each request instead of the current single 
window.__onXHRLocalCallback.

> XHRHelper is failing with simultaneous asynchronous requests
> ------------------------------------------------------------
>
>                 Key: CB-4873
>                 URL: https://issues.apache.org/jira/browse/CB-4873
>             Project: Apache Cordova
>          Issue Type: Bug
>          Components: WP7, WP8
>    Affects Versions: 3.0.0
>         Environment: Any
>            Reporter: Jonathan Naguin
>            Assignee: Jesse MacFadyen
>            Priority: Critical
>              Labels: WP8, ajax, asynchronous, multiple, xhrhelper
>
> XHRHelper is failing in processing mutiple simultaneous asynchronous AJAX 
> requests. I am using the latest code from 
> https://github.com/apache/cordova-wp8/blob/master/wp8/template/cordovalib/XHRHelper.cs
> The problem is related with {{_onXHRLocalCallback}} which is save into the 
> {{window}} object as a unique function. When, for example, two Ajax requests 
> are evaluated at same time, the last {{funk}} function overrides the first 
> {{_onXHRLocalCallback}} without receive the data from the C# code to that 
> particular request.
> To demostrate this I put {{console.log("XHR: " + resolvedUrl);}} inside 
> {{__onXHRLocalCallback}} and 
> {{System.Diagnostics.Debug.WriteLine("HandleCommand: " + url);}} in 
> {{HandleCommand}} method (my code uses *Require JS* to load this resources). 
> The output is this:
> {code}
> HandleCommand: x-wmapp0:www/src/modules/home/HomeView.html
> HandleCommand: x-wmapp0:www/src/modules/orders/OrdersView.html
> XHR: x-wmapp0:www/src/modules/orders/OrdersView.html
> XHR: x-wmapp0:www/src/modules/orders/OrdersView.html
> XHR: HandleCommand: x-wmapp0:www/src/modules/order/OrderDetailView.html
> XHR: x-wmapp0:www/src/modules/order/OrderDetailView.html
> {code}
> As you can see, one request is missing: "HomeView.html".
> h6. NOTES
> - If I set {{false}} the {{this.isAsync}} variable it works (this way it is 
> executed without using setTimeout).
> - If I put a console.log before launch {{funk}} it works.
> - It works on the simulator, but it fails on a real device.
> h6. Possible solution
> In conclusion, I assumed that it's a timing problem. To resolve it I decided 
> to save a onXHRLocalCallback function per each request:
> {code}
> var funk = function () {
>     if (! window.__onXHRLocalCallback){
>         window.__onXHRLocalCallback = {}; //Object to store the functions
>     }
>     
>     window.__onXHRLocalCallback[resolvedUrl] = function (responseCode, 
> responseText) {
>         alias.status = responseCode;
>         if (responseCode == '200') {
>             alias.responseText = responseText;
>         }
>         else {
>             alias.onerror && alias.onerror(responseCode);
>         }
>         alias.changeReadyState(XHRShim.DONE);
>         delete window.__onXHRLocalCallback[resolvedUrl]; //Delete the function
>     }
>     alias.changeReadyState(XHRShim.LOADING);
>     window.external.Notify('XHRLOCAL/' + resolvedUrl);
> }
> {code}
> So I had to change in {{HandleCommand}} method the way of invoking this 
> callback. I decided to create a helper function to be called in each case:
> {code}
> /// <summary>
> /// Invoke a XHR callback
> /// </summary>
> /// <param name="url">The URL of the request</param>
> /// <param name="code">The response code</param>
> /// <param name="text">The response text</param>
> private void InvokeCallback(string url, int code, string text)
> {
>     string args = string.Format("('{0}', {1}, {2});", code, 
> WPCordovaClassLib.Cordova.JSON.JsonHelper.Serialize(text), 
> WPCordovaClassLib.Cordova.JSON.JsonHelper.Serialize(url));
>     string callback = @"(function(code, text, url){
>       try {
>           window.__onXHRLocalCallback[ url ].call(null, code, text);
>       }
>       catch(e) {
>           console.log('Error calling method from XHRHelper :: ' + e);
>       }
>     })" + args;
>     Browser.InvokeScript("eval", new string[] { callback });
> }
> {code}
> To be called as {{InvokeCallback(url, 200, text);}} or {{InvokeCallback(url, 
> 404, null);}}
> Thanks.



--
This message was sent by Atlassian JIRA
(v6.2#6252)

Reply via email to