Details
-
Bug
-
Status: Closed
-
Critical
-
Resolution: Fixed
-
3.0.0
-
None
-
Any
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
Attachments
Issue Links
- relates to
-
CB-6763 Simultaneous local XHRs on WP8 returns incorrect result
- Closed