Problem description
Under jquery or Zepto, the same jsonp is called in a loop
for(vari =0;i<5; i++{$.ajax ({URL:'https://m.suning.com/authStatus?callback=checkLogin1&_=1430100870770', DataType:'Jsonp', Jsonpcallback:'checkLogin1', Success:function (data) {Console.info ('Success'); }, Error:function (xhr,e) {console.error (e); } }); }
Results
Some successes, some failures? Why is this?
Explanation of the problem
Observe the source code of JSONP
/** * JSONP Request * @param options * @param deferred * @returns {*}*/$.ajaxjsonp=function (options, deferred) {//without setting the type, go to Ajax and let the parameters initialize. //such as direct call Ajaxjsonp,type not set if(! ('type' inchOptions))return$.ajax (Options)var_callbackname = Options.jsonpcallback,//callback function nameCallbackname = ($.isfunction (_callbackname)?_callbackname (): _callbackname)|| ('Jsonp'+ (++jsonpid)),//no callback, assign default callbackScript = Document.createelement ('Script'), Originalcallback= Window[callbackname],//callback functionResponseData,//Interrupt request, throw Error event//This does not necessarily interrupt script loading, but prevents the execution of the callback function belowAbort =function (ErrorType) {$ (script). Triggerhandler ('Error', ErrorType | |'Abort')}, XHR={abort:abort}, Aborttimeout//XHR is read-only deferred if(deferred) deferred.promise (XHR)//Load Error event when monitoring is loaded$ (script). On ('Load Error', Function (e, errorType) {//Purge Timeout setting timeoutcleartimeout (aborttimeout)//Delete the script that was loaded. Because it's finished loading .$ (script). Off (). Remove ()//Wrong call error if(E.type = ='Error'|| !responsedata) {Ajaxerror (NULL, ErrorType | |'Error', XHR, Options, deferred)} Else { //successfully called successAjaxsuccess (responsedata[0], XHR, Options, deferred)}//callback functionWindow[callbackname] =Originalcallbackif(ResponseData &&$.isfunction (Originalcallback)) Originalcallback (responsedata[0]) //clears the value of the variable referenced by the closure, does not empty, and the parent function can be freed if the closure is released. Empty, the parent function can be released directlyOriginalcallback = ResponseData =undefined}) if(Ajaxbeforesend (XHR, options) = = =false) {Abort ('Abort') returnXHR}//callback function settings, for background executionWindow[callbackname] =function () {/*console.info (' callbackname arguments '); Console.info (Arguments[0]);*/ResponseData=arguments/*console.info (' responsedata '); Console.info (responsedata);*/ } //the callback function is appended to the request addressSCRIPT.SRC = Options.url.replace (/\? +)=\?/,'? $1='+callbackname) document.head.appendChild (script)//time-out processing via settimeout delay processing if(Options.timeout >0) Aborttimeout =setTimeout (function () {Abort ('Timeout')}, Options.timeout)returnXHR}
The problem is with multithreading. When the first JSONP has just finished executing callback and assigned a value, the script's Load event has not yet been triggered. The second JSONP begins to initialize. Then the load of the first script starts executing, but its data is cleared out.
The first JSONP just finished executing callback, and the response data was assigned to ResponseData
// callback function settings, for background execution Window[callbackname] = function () { /* console.info (' callbackname arguments '); Console.info (Arguments[0]); */ = arguments /*console.info (' responsedata '); Console.info (responsedata); */ }
The second JSONP begins to initialize. Yes, ResponseData was again assigned to undefine!!!.
The load of the first script begins to execute, responsedata at this point is absolutely undefined, for Mao? Because this is a closure, the value of the last ResponseData is referenced. can only enter the error.
Problem fix
Policy :
1, modify the JSONP source code. When the callback is executed, the ResponseData is passed into the listener function. such as function (data) {return function (.... onload ...} (responsedata); This is too cumbersome, and you have to pay attention to the open source protocol.
2, avoid the response of JSONP. Changed to such a way of writing. The principle is that the request is made only with JSONP, and then the Window.callback is executed in the background.
window.checklogin1 = '
Remember not to add Jsonpcallback: ' checkLogin1 '. The reason is that JSONP overrides Window[checklogin1]. The second request will not be found.
// callback function settings, for background execution Window[callbackname] = function () { /* console.info (' callbackname arguments '); Console.info (Arguments[0]); */ = arguments /*console.info (' responsedata '); Console.info (responsedata); */ }
JSONP does not support circular calls