Skip to main content

Bug Tracker

Side navigation

#8744 closed bug (cantfix)

Opened April 01, 2011 04:46PM UTC

Closed January 26, 2013 09:35PM UTC

Last modified April 01, 2013 03:51AM UTC

.ajax() jsonp requests are not handled correctly when hitting timeout

Reported by: Dynalon Owned by: jaubourg
Priority: high Milestone: 1.next
Component: ajax Version: 1.5.2
Keywords: jsonp timeout Cc: jaubourg
Blocked by: Blocking:
Description

The $.ajax() call does not handle cross-domain JSONP requests correctly if the request fails because of a timeout.

As soon as the timeout was reached, the corresponding callbacks error/complete/success are fired correctly. However, the xhr is not canceled and after response (even if its too late now) jQuery jumps into the callback handler of the jsonp, even so the function does not exists (anymore). You will hit an error like "jQuery152008986116735648775_1301675055297 is not a function" in your error console.

(quite) minimal testcase which will always timeout:

function doTest() {
    $.ajax({
        url: 'http://jsfiddle.net/echo/jsonp/',
        timeout: 5,
        dataType: "jsonp",
        data: { echo: "Hello World!" },
        error: function(jqxhr, textStatus) {
            console.log("failed with error: " + textStatus);
        },
        success: function(data, jqxhr, textStatus) {
            alert(data.echo);   
        }
    });
}
$("document").ready(doTest);

// attention: you cannot run that  testcase on jsFiddle because
// it will then not be a cross-domain request!

If you set the timeout in the code above to a reasonable timeframe, i.e. 5000, the cross-domain request will finish properly.

Expected behaviour: jQuery should correctly cancel the XHR when hitting the timeout.

Tested Browser: Firefox 4 and Opera 11 are both affected, Safari 5 however seems not to be (all tested on Mac).

Attachments (0)
Change History (38)

Changed April 02, 2011 05:17PM UTC by timmywil comment:1

cc: → jaubourg
component: unfiledajax
keywords: → jsonp timeout

Unfortunately, and jaubourg can correct me on this, but I don't think it can be cancelled since jsonp is not xhr.

Changed April 02, 2011 08:02PM UTC by Dynalon comment:2

I've digged into this a little more and yes, it seems the problem is not easily solveable. The JSONP request is done via injection of a <script> tag into the DOM and I don't think (?) there is a way to cancel the request once its triggered. The problem is, the callback function is removed from the window context by jquery right after hitting the timeout. If the request does finish later, the jsonp response is run by the browser as a standalone-script and thus first hits an undefined function, causing the "unknown function" exception.

However, it turns out that this bug is a really minor one. As the exception is thrown in the standalone script of the jsonp response, it should not affect any other scripts running, causing no damage at all except for the error messge in the error console.

I've come up with a simple hack in jquery so that the callback function is not cleaned up and remains within the window object. This resolves the problem but is surely no feasible solution for upstream since the window object would be cluttered with (afterwards useless) functions over time when doing lots of jsonp requests.

To have this completeley fixed a better way for callback handling would be needed, but considering that the bug itself doesn't raise serious issues I think its not worth the effort.

Changed April 02, 2011 11:03PM UTC by jaubourg comment:3

_comment0: I find this behaviour very strange. I'm not on my dev box right now but afaik, jqXHR.abort (which is used by timeout) will remove the script tag from the node... so is it that FF4 and Opera 11 don't cancel script loading in that case or is something wrong in the script tag removal code? \ \ I'll look into this on my dev box once I'm back on it.1301785434593249
owner: → jaubourg
status: newassigned

I find this behaviour very strange. I'm not on my dev box right now but afaik, jqXHR.abort (which is used by timeout) will remove the script tag from the document... so is it that FF4 and Opera 11 don't cancel script loading in that case or is something wrong in the script tag removal code?

I'll look into this on my dev box once I'm back on it.

Changed April 04, 2011 03:41PM UTC by jaubourg comment:4

resolution: → fixed
status: assignedclosed

Fixes #8744. Makes sure script transport abort method actually removes the script tag even if readyState exists.

Changeset: 2ed81b44be958b5f2b5569ab15f22bde262b4eb6

Changed April 04, 2011 03:42PM UTC by jaubourg comment:5

Dynalon, can you confirm this fixes your issue?

Changed April 04, 2011 03:51PM UTC by jaubourg comment:6

milestone: 1.next1.6

Changed April 04, 2011 04:15PM UTC by Dynalon comment:7

Yes, I confirm with the recent git version the problem is gone, bug is fixed. Thanks!

Changed April 04, 2011 04:26PM UTC by Dynalon comment:8

Stop, that one was to quick: The Bugfix in Git works for Opera 11 (Mac & Linux tested), but is still present in Firefox 3.6.13 (Linux) and Firefox 4 (Mac). So the Fix does not seem to work on Firefox at all.

Changed April 04, 2011 07:05PM UTC by timmywil comment:9

I think jaubourg had the right idea about firefox script loading. Once the script tag is injected, I believe it loads the script regardless of whether the tag gets removed before completion. Another thought I had was that I think async is set to true by default for injected script tags in Firefox 4. I'm not sure if that could have an impact on removals. Again, I defer to jaubourg on these issues.

Changed April 04, 2011 11:36PM UTC by jaubourg comment:10

Dynalon: could you set a test case on jsFiddle (calling the twitter public api or whatnot). I'd like to see this with my own eyes because, if that's the case and what timmywil says is right then it's clearly a bug in Firefox. I highly doubt it though, so I'll need a test case clearly showing the behaviour to re-open this (are you sure you didn't have some caching issues when you tested in FF?).

Changed April 05, 2011 12:06AM UTC by Dynalon comment:11

_comment0: Yes, actually it seems if you enforce dataType:jsonp as ajax option, the bug appears not matter if cross-domain or not. So I now have set up a testcase on jsFiddle: \ \ http://jsfiddle.net/XtVWT/ \ \ Please note the HTML Commentin jsFiddle, it seems there is a problem with git-edge on jsFiddle / code.jquery.com/jquery-git.js \ \ As already said, with you fix in jquery-git the Bug does not occur in Opera, but is still present in FF when testing with this fiddle.1301962046487691

Yes, actually it seems if you enforce dataType:jsonp as ajax option, the bug appears no matter if cross-domain or not. So I now have set up a testcase on jsFiddle:

http://jsfiddle.net/XtVWT/

Please note the HTML Commentin jsFiddle, it seems there is a problem with git-edge on jsFiddle / code.jquery.com/jquery-git.js

As already said, with you fix in jquery-git the Bug does not occur in Opera, but is still present in FF when testing with this fiddle.

Changed April 05, 2011 04:25AM UTC by jaubourg comment:12

keywords: jsonp timeoutjsonp timeout needsdocs

OK, so I checked this under FF and it seems timmy is right: once the script tag has been appended, there seems to be no way to cancel loading. This is quite daunting seeing as it means there is no mean to abort cross-domain script requests in FF. I tried with and without async to no avail :(

This is clearly a bug in the browser. We need to document the issue.

Changed April 23, 2011 06:10PM UTC by john comment:13

priority: undecidedhigh

Changed June 29, 2011 03:30PM UTC by addyosmani comment:14

milestone: 1.6
resolution: fixed
status: closedreopened

Changed June 29, 2011 03:32PM UTC by addyosmani comment:15

@jaubourg: as this ticket has been open for two months, can you re-confirm whether it's been fixed or if any fixes are currently being worked on for it? thanks!

Changed June 29, 2011 04:10PM UTC by jaubourg comment:16

It's a FF bug. The script tag is removed, yet the script is still loaded and executed... didn't check if this was fixed in FF5.

Changed June 29, 2011 07:20PM UTC by timmywil comment:17

status: reopenedopen

Changed June 30, 2011 03:58PM UTC by jaubourg comment:18

#9687 is a duplicate of this ticket.

Changed July 08, 2011 03:37PM UTC by addyosmani comment:19

keywords: jsonp timeout needsdocsjsonp timeout neededdocs

Changed July 11, 2011 04:46PM UTC by john comment:20

milestone: → 1.next

Changed July 15, 2011 05:25PM UTC by jaubourg comment:21

#9782 is a duplicate of this ticket.

Changed July 18, 2011 01:48PM UTC by timmywil comment:22

#9853 is a duplicate of this ticket.

Changed November 24, 2011 12:46AM UTC by blair comment:23

When i load this jsfiddle code: http://jsfiddle.net/XtVWT/

I always get an error in IE9 stating "Object expected". Clicking debug error points me to this line:

jQuery1604361509936638372_1322095521345({"_": "1322095521358", "echo": "Hello World!"});

This is a huge issue for us and hope it can get fixed soon.

Changed November 24, 2011 05:32AM UTC by Dynalon comment:24

@blair: the jsFiddle you posted uses an old version of jquery, because at the time i reported the bug, jsFiddle has had issues with using jquery-edge, which is was likely fixed weeks ago.

I set up a new fiddle here: http://jsfiddle.net/HEsL2/ which you can use to test against jquery-edge. Can you confirm IE9 is affected, and if so, whether or not you are getting the "failed with error: timeout" message?

If you get the "right" error message that means the error() event is correctly triggered when hitting the timeout. If thats the case, the bug should not be a huge issue as the code will work as expected - the only drawback is the somewhat confusing error message that is displayed on the error console.

Changed November 24, 2011 06:00AM UTC by blair comment:25

@Dynalon

With your new example I still get the "Object Expected" error in IE9:

jQuery1725116137489204307943349415308069850127750664_1322114277554({"_": "1322114277629", "echo": "Hello World!"});

Also note that IE9 does not print its errors to the console, the error comes in the form of a modal alert dialog. This is a critical error that should be fixed asap as users with error messaging enabled in IE9 will always see this issue if the timeout hits, providing a less than ideal user experience.

Changed November 24, 2011 07:45AM UTC by Dynalon comment:26

so you say IE9 will fail completely if the timeout hits? I agree, in this case this is a major issue. However, the whole thing isn't really jquery's fault, but specific to the browser implementations. To really fix the bug, one must nag the IE & FF developers to fix this in their code.

I don't think there is a *good* way to work around this in jquery for those browsers. The only workaround I came up with, is to prevent jquery from deleting the jsonp callback function when the timeout is encountered. Instead, upon timeout hit, the callback function is replaced by an empty dummy function which does nothing. So if - at a later time- the ajax request completes (even if the timeout was hit already) the browser actually finds the function.

This is UGLY AS HELL, as references to the callback functions are stored PERMANENTLY in the window object, thus cluttering the heap more and more everytime you do a jsonp request that exceeds its timeout.

If you can live with that and only do a limited amount of requests on a page, I've uploaded a patch that implements this workaround, grab it here: http://www.stud.uni-karlsruhe.de/~urblr/jquery-ugly/workaround-bug8744.diff

To test jquery with applied patch see: http://jsfiddle.net/D5YUZ/

At least it fixes the issues in FF for me (can't test in IE since I don't have a windows box around).

Once again, this is not a good solution and the patch is not meant to be put into upstream jquery, so you've been warned!

Changed November 24, 2011 07:54AM UTC by anonymous comment:27

Dynalon thanks for the reply, to clarify, the error callback is called into, but in addition, there is the "Object expected" error alert.

Changed November 24, 2011 07:58AM UTC by anonymous comment:28

Dynalon, your patch also fixes IE9 from throwing the "Object expected" error. It also correctly executes the ajax error callback.

I agree that cluttering the global namespace with callback functions is not a good solution, wondering if there is a better way.

Changed November 24, 2011 09:05AM UTC by jaubourg comment:29

Yeah, this is a nasty nasty bug but Dynalon is spot on: the right fix is browser-side :(

Changed November 24, 2011 09:32AM UTC by Dynalon comment:30

Turns out the bug is known since 2007 in FF but due to lack of reporter corresponding it never got fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=394908

Also, the Dojokit is aware of this bug, see: http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/tests/io/scriptTimeout.html

I've resurrected the bugreport in mozillas bugzilla and hopefully it can be worked out in FF.

Since I have no access to a windows machine to verify IE8/9 behaviour, could someone with windows report that bug to Microsoft and have them work it out?

Changed November 24, 2011 09:51AM UTC by BennyTheSnitch comment:31

The following work-around was suggested a few months back in a different post:

window.jQuery16207753935731721285_1310374972748 = function() {

    delete window.jQuery16207753935731721285_1310374972748;

}

Although the global namespace would still be littered with redundant callbacks at least the ones that DO eventually return would be removed.

Changed November 24, 2011 10:50AM UTC by jaubourg comment:32

Replying to [comment:31 BennyTheSnitch]:

The following work-around was suggested a few months back in a different post:
> window.jQuery16207753935731721285_1310374972748 = function() {
> 
>     delete window.jQuery16207753935731721285_1310374972748;
> 
> }
> 
Although the global namespace would still be littered with redundant callbacks at least the ones that DO eventually return would be removed.

On browsers that do handle removing a script tag properly or, in all browsers when you have a server error or the jsonp response is illformed and never calls the function, these would stay in the global namespace.

So it's still not an acceptable solution.

Changed December 13, 2011 01:30AM UTC by anonymous comment:33

Hi, what is the best workaround for this issue?

Changed March 23, 2012 11:02AM UTC by e.marin.izquierdo@gmail.com comment:34

My solution:

 // JSON Request
   var auxTime = new Date();
   var jQueryCallbackRandom = auxTime.getTime();
		
   var callParameters = {
      url: myUrl,
      dataType: "jsonp",			
      jsonp: "myServerParamCallback",
      jsonpCallback: "jQueryRandom_" + jQueryCallbackRandom,
      crossDomain : true,
      success: f_success,
      timeout: myCriticTimeOut,
      error: function(jqXHR, textStatus){
         console.log("failed with error: " + textStatus);
         window["jQueryRandom_" + jQueryCallbackRandom] = function( {window["jQueryRandom_" + jQueryCallbackRandom] = null;};
      },
      data: params			
   }
   
   $.ajax(callParameters);
	

Changed October 26, 2012 05:24PM UTC by anonymous comment:35

I've found this to still be an issue on at least IE9 and Windows Chrome. Replies #26, #32, and #34 successfully address it, but all will leave empty functions... Because I don't want to amend jQuery as in #26, I modified the answers in #32 and #34, see the following jsfiddle. Also, this doesn't require pre-defined jsonpCallback as in #34. Note this still leaves empty functions in the namespace...

http://jsfiddle.net/2qnrU/

Note that there's probably a there a better way to grab the pre-defined AJAX callback? I just found the callback as a property of the object, so I pulled the name with a for-in loop.

Changed October 26, 2012 05:26PM UTC by anonymous comment:36

Sorry I didn't realize using a # sign triggered links to tickets. I was referring to comment numbers.

Changed January 26, 2013 09:35PM UTC by dmethvin comment:37

keywords: jsonp timeout neededdocsjsonp timeout
resolution: → cantfix
status: openclosed

It's pretty clear we can't make this work cross-browser, it will have to be solved by the browser makers. some workarounds are listed above. The related Firefox ticket is here:

https://bugzilla.mozilla.org/show_bug.cgi?id=707154

Docs ticket is here:

https://github.com/jquery/api.jquery.com/issues/235

Please don't add more comments to the ticket unless they contribute **significantly** to the discussion.

Changed April 01, 2013 03:51AM UTC by markelog comment:38

#13693 is a duplicate of this ticket.