Jonathan Naguin created CB-4873:
-----------------------------------
Summary: 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
XHRHelper is failing in processing mutiple simultaneous asynchronous AJAX
requests.
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 is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira