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

XHRHelper is failing with simultaneous asynchronous requests

    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_WP8.1_3.4.1.zip
          242 kB
          Maris Seimanovs
        2. CordovaWP8_3.6.0-dev1.zip
          229 kB
          Jesse MacFadyen

        Issue Links

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved: