Uploaded image for project: 'Apache Cordova'
  1. Apache Cordova
  2. CB-4873

XHRHelper is failing with simultaneous asynchronous requests

VotersWatch issueWatchersLinkUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments
    XMLWordPrintableJSON

Details

    Description

      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:

      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
      

      As you can see, one request is missing: "HomeView.html".

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

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

      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:

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

      To be called as InvokeCallback(url, 200, text); or InvokeCallback(url, 404, null);

      Thanks.

      Attachments

        1. CordovaWP8_3.6.0-dev1.zip
          229 kB
          Jesse MacFadyen
        2. CordovaWP8_WP8.1_3.4.1.zip
          242 kB
          Maris Seimanovs

        Issue Links

        Activity

          This comment will be Viewable by All Users Viewable by All Users
          Cancel

          People

            purplecabbage Jesse MacFadyen
            jonathannaguin Jonathan Naguin
            Votes:
            6 Vote for this issue
            Watchers:
            7 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Slack

                Issue deployment