JSONP不支持循环调用
问题描述
在jquery或zepto下,循环调用同一个jsonp
for(var i = ;i<;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);
}
});
}
结果

有些成功有些失败了?这是为何?
问题解释
观察jsonp的源码
/**
* jsonp请求
* @param options
* @param deferred
* @returns {*}
*/
$.ajaxJSONP = function(options, deferred){
//未设置type,就走 ajax 让参数初始化.
//如直接调用ajaxJSONP,type未设置
if (!('type' in options)) return $.ajax(options) var _callbackName = options.jsonpCallback, //回调函数名
callbackName = ($.isFunction(_callbackName) ?
_callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), //没有回调,赋默认回调
script = document.createElement('script'),
originalCallback = window[callbackName], //回调函数
responseData, //中断请求,抛出error事件
//这里不一定能中断script的加载,但在下面阻止回调函数的执行
abort = function(errorType) {
$(script).triggerHandler('error', errorType || 'abort')
},
xhr = { abort: abort }, abortTimeout //xhr为只读deferred
if (deferred) deferred.promise(xhr) //监听加载完,加载出错事件
$(script).on('load error', function(e, errorType){
//清除超时设置timeout
clearTimeout(abortTimeout) //删除加载用的script。因为已加载完了
$(script).off().remove() //错误调用error
if (e.type == 'error' || !responseData) {
ajaxError(null, errorType || 'error', xhr, options, deferred)
} else {
//成功调用success
ajaxSuccess(responseData[], xhr, options, deferred)
} //回调函数
window[callbackName] = originalCallback
if (responseData && $.isFunction(originalCallback))
originalCallback(responseData[]) //清空闭包引用的变量值,不清空,需闭包释放,父函数才能释放。清空,父函数可以直接释放
originalCallback = responseData = undefined
}) if (ajaxBeforeSend(xhr, options) === false) {
abort('abort')
return xhr
} //回调函数设置,给后台执行
window[callbackName] = function(){
/* console.info('callbackName arguments ');
console.info(arguments[0]);*/
responseData = arguments
/*console.info('responseData ');
console.info(responseData);*/
} //回调函数追加到请求地址
script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
document.head.appendChild(script) //超时处理,通过setTimeout延时处理
if (options.timeout > ) abortTimeout = setTimeout(function(){
abort('timeout')
}, options.timeout) return xhr
}
问题出在多线程处理。 当第一个jsonp刚执行完callback,赋了值时,此时,script的load事件还未触发。第二个JSONP开始初始化。然后第一个script的load开始执行,但它的数据已被清掉了
第一个jsonp刚执行完callback,响应数据赋给了 responseData
//回调函数设置,给后台执行
window[callbackName] = function(){
/* console.info('callbackName arguments ');
console.info(arguments[0]);*/
responseData = arguments
/*console.info('responseData ');
console.info(responseData);*/
}
第二个JSONP开始初始化。没错 responseData又被赋为undefine!!!

第一个script的load开始执行,responseData这时判断绝对为undefined,为毛?因为这是闭包,引用最后一个responseData的值。只能进入error了。

问题修复
策略:
1, 修改jsonp源码。在执行callback时,将responseData,传入监听函数。诸如function(data){ return function( ...onload... }(responseData);这个太麻烦,而且还得注意开源协议。
2,规避jsonp的响应。改成这样一种写法。原理是,只用jsonp发请求,然后后台执行window.callback。
window.checkLogin1 = function(data){
console.info('checkLogin1 success');
console.info(data);
}
for(var i = ;i<;i++){
$.ajax({
url:'https://m.suning.com/authStatus?callback=checkLogin1&_=1430100870770',
dataType:'jsonp'
});
}
切记不能加 jsonpCallback:‘checkLogin1’.原因是,jsonp会重写window[checkLogin1].第二次请求将找不到。
//回调函数设置,给后台执行
window[callbackName] = function(){
/* console.info('callbackName arguments ');
console.info(arguments[0]);*/
responseData = arguments
/*console.info('responseData ');
console.info(responseData);*/
}
JSONP不支持循环调用的更多相关文章
- Python函数的循环调用
def foo (): print 'runing foo' bar () def bar (): print 'runing bar' foo () bar() 直接上脚本,上面的脚本如果换成C语言 ...
- jsonp 跨域只能调用一次ajax(无法多次调用或者循环调用)
jsonp 跨域只能掉用一次ajax(无法多次调用或者循环调用) 百度搜索关键字:jsonp 只能调用一次ajax 解决方法 //回调函数设置,给后台执行 window[callback ...
- lua序列化(支持循环引用)
lua序列化 支持key类型为string, number 支持value类型为string, number, table, boolean 支持循环引用 支持加密序列化 支持loadstring反序 ...
- MVC.Net:WebAPI添加对jsonP的支持
在某些情况下,我们需要在WebAPI项目中添加对jsonP的支持.比如我们同时创建了MVC.Net和WebAPI两个项目,这两个项目使用不同的端口,这时如果MVC.Net项目的前端想要直接访问WebA ...
- 03server平台delphi程序不支持直接调用webservice
经过多次测试和查证,发现03server平台用delphi7.0开发的应用程序就是不支持直接调用webservice,无论这个webservice是delphi开发的还是C#开发,抑或是java开发的 ...
- jmeter之regular expression extractor ,并循环调用匹配到的多个值
jmeter之regular expression extractor 官方介绍:http://jmeter.apache.org/usermanual/regular_expressions.htm ...
- Oracle之带参存储过程(存储过程中for循环调用存储过程)
--带参存储过程create or replace procedure testdate(v in number) is i number; begin i:=v; insert into test_ ...
- Sybase:循环调用存储过程
Sybase:循环调用存储过程 一.日期循环 declare @c_count int declare @rq int --获取两个日期之间的天数 ,getdate()) begin ,),),),) ...
- 使用jackson转json解决双向关联循环调用
ITOO V1.0的开发算是告一段落了,现在是整理总结交接环节,在这个项目中常见的问题也该好好整理一下和大家分享了,这次主要介绍转json循环调用的问题. 一.问题背景 相信只要使用ORM映射实体关联 ...
随机推荐
- 爬虫入门系列(二):优雅的HTTP库requests
在系列文章的第一篇中介绍了 HTTP 协议,Python 提供了很多模块来基于 HTTP 协议的网络编程,urllib.urllib2.urllib3.httplib.httplib2,都是和 HTT ...
- Java中boolean类型占用多少个字节
为什么要问这个问题,首先在Java中定义的八种基本数据类型中,除了其它七种类型都有明确的内存占用字节数外,就boolean类型没有给出具体的占用字节数,因为对虚拟机来说根本就不存在 boolean 这 ...
- 浅谈echo、print、var_dump()、print_r()的区别
1.echo 和 print 的区别 共同点:首先echo 和 print 都不是严格意义上的函数,他们都是语言结构;他们都只能输出 字符串,整型跟int型浮点型数据.不能打印复合型和资源型数据: 而 ...
- js创建xml对象
js创建xml对象 //创建对象 function getDataXML() { var objTds = $("TEXTAREA"); var count = o ...
- Node.js系列:Buffer类的使用
客户端JavaScript中没有对二进制数据提供很好的支持.但是在处理TCP流或文件流时,必须要处理二进制数据.Node.js定义了一个Buffer类,用来创建一个专门存放二进制数据的缓存区. Buf ...
- 本学期微分方程数值解课程总结(matlab代码)
最简单求解一个微分方程数值解得方法:Euler法 function [x,y]=Euler_method(dufun,span,h,x0,y0) %EuLer格式, %求解方程y'=dufun(x,y ...
- MAC Mysql 重置密码
使用mac电脑,当mysql登录密码忘记时,需要重置密码.步骤如下: 1. 关闭当前正在运行的mysql进程. A.进入"偏好设置",选择mysql, 再选"stop m ...
- java抽象类和抽象方法之间的关系
抽象类和抽象方法之间的关系有抽象方法的类,一定是抽象类:抽象类不一定有抽象方法当子类继承抽象类时,必须要将抽象类中的抽象方法全部实现(或者称为重写),否则子类依然是抽象类因为子类是继承父类全部内容,所 ...
- react+redux+generation-modation脚手架添加一个todolist
当我遇到问题: 要沉着冷静. 要管理好时间. 别被bug或error搞的不高兴,要高兴,又有煅炼思维的机会了. 要思考这是为什么? 要搞清楚问题的本质. 要探究问题,探究数据的流动. TodoList ...
- 使用Spigot搭建MineCraft服务器
MineCraft 这种游戏还是人多了好玩,以前的服务器放在同学的Windows电脑上,每次我们想玩的时候就让让去打开,但是总是有一些原因,想玩的时候服务器没开着,不想玩的时候服务器空开着费电.昨天一 ...