@@ -226,7 +226,7 @@ var extend = _dereq_('extend');
226226
227227var util = _dereq_ ( './util' ) ;
228228
229- // Superagent uses btoa for auth encoding on the client, which is missing from <IE10
229+ // SuperAgent uses btoa for auth encoding on the client, which is missing from <IE10
230230// https://github.com/visionmedia/superagent#supported-browsers
231231if ( ! util . isNode && ! window . btoa ) window . btoa = _dereq_ ( './base64' ) . encode ;
232232
@@ -381,18 +381,36 @@ var jsonpRequest = function(method, data, callback) {
381381 script . src = url ;
382382
383383 var timer ;
384- var jsonpCallback = _ . once ( function ( data ) {
385- document . getElementsByTagName ( 'head' ) [ 0 ] . removeChild ( script ) ;
386- if ( data instanceof Error ) return callback ( data ) ;
387- if ( timer ) clearTimeout ( timer ) ;
388- processResponse ( { status : 200 } , data , callback ) ;
389- } ) ;
384+ var first = true ;
385+
386+ window [ callbackName ] = function ( data ) {
387+ var timedout = data instanceof Error ;
388+
389+ // Cancel timeout
390+ if ( timer ) {
391+ clearTimeout ( timer ) ;
392+ timer = null ;
393+ }
390394
391- window [ callbackName ] = jsonpCallback ;
395+ // Do not cleanup if there was a timeout, in case the real request ever comes back
396+ if ( ! timedout ) {
397+ document . getElementsByTagName ( 'head' ) [ 0 ] . removeChild ( script ) ;
398+ delete window [ callbackName ] ;
399+ }
400+
401+ // Only run user callback once
402+ if ( first ) {
403+ first = false ;
404+ timedout ? callback ( data ) : processResponse ( { status : 200 } , data , callback ) ;
405+ }
406+ } ;
392407
393408 if ( self . options . timeout ) {
394409 timer = setTimeout ( function ( ) {
395- jsonpCallback ( new Error ( 'timeout of ' + self . options . timeout + 'ms exceeded' ) ) ;
410+ timer = null ;
411+ var err = new Error ( 'timeout of ' + self . options . timeout + 'ms exceeded' ) ;
412+ err . callbackName = callbackName ; // For testing purposes
413+ window [ callbackName ] ( err ) ;
396414 } , self . options . timeout ) ;
397415 }
398416
@@ -448,12 +466,20 @@ var superAgentRequest = function(request, callback) {
448466 // http://visionmedia.github.io/superagent/#buffering-responses
449467 if ( request . buffer ) request . buffer ( ) ;
450468
451- request . end ( function ( err , res ) {
452- // Superagent considers statuses <200 and >=300 as errors
453- // http://visionmedia.github.io/superagent/#error-handling
454- if ( err ) return callback ( err , res ) ;
455- processResponse ( res , null , callback ) ;
456- } ) ;
469+ // Not all weird browser errors are catched by SuperAgent
470+ try {
471+ request . end ( function ( err , res ) {
472+ // In case the request is not async, we don't want to catch the callback exceptions
473+ setTimeout ( function ( ) {
474+ // SuperAgent considers statuses <200 and >=300 as errors
475+ // http://visionmedia.github.io/superagent/#error-handling
476+ if ( err ) return callback ( err , res ) ;
477+ processResponse ( res , null , callback ) ;
478+ } , 0 ) ;
479+ } ) ;
480+ } catch ( err ) {
481+ callback ( err ) ;
482+ }
457483}
458484
459485var processResponse = function ( res , data , callback ) {
@@ -493,7 +519,7 @@ module.exports = Resource;
493519} , { "./base64" :2 , "./util" :4 , "extend" :6 , "qs" :110 , "superagent" :115 , "underscore" :118 } ] , 4 :[ function ( _dereq_ , module , exports ) {
494520module . exports . isNode = ! ( typeof window !== 'undefined' && window !== null ) ;
495521
496- module . exports . supportsCORS = ! module . exports . isNode && ( ( 'withCredentials' in new XMLHttpRequest ( ) ) || ( typeof XDomainRequest !== 'undefined' ) ) ;
522+ module . exports . supportsCORS = ! module . exports . isNode && ( typeof XMLHttpRequest !== 'undefined' ) && ( 'withCredentials' in new XMLHttpRequest ( ) ) ;
497523
498524} , { } ] , 5 :[ function ( _dereq_ , module , exports ) {
499525var _ = _dereq_ ( 'underscore' ) ;
0 commit comments