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映射实体关联 ...
随机推荐
- 非负矩阵分解(4):NMF算法和聚类算法的联系与区别
作者:桂. 时间:2017-04-14 06:22:26 链接:http://www.cnblogs.com/xingshansi/p/6685811.html 声明:欢迎被转载,不过记得注明出处 ...
- php判断多维数组的技巧
直接上代码吧: if(count($array) == count($array, 1)){ echo '一维数组'; }else{ echo '多维数组'; } 看了下手册 int count (m ...
- sql中常见日期获取
获取当前年月日 --获取当前月份 ,GETDATE())) --获取当前月份的下个月 ,GETDATE())) --获取当前月份的上个月 year()获取年 select year(GETDATE() ...
- WinForm中控件位置不随窗体大小的变化而改变
背景:在窗体开发中使控件的位置不随窗体的大小改变而变化的问题?这是一个同事在开发时遇到的问题,在思考试错之后,写出如下代码. 声明成员: Point m_InitLocation; Size m_In ...
- 深度学习入门实战(二)-用TensorFlow训练线性回归
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者 :董超 上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能 ...
- Let's Encrypt: 为CentOS/RHEL 7下的nginx安装https支持-具体案例
环境说明: centos 7 nginx 1.10.2 前期准备 软件安装 yum install -y epel-release yum install -y certbot 创建目录及链接 方法1 ...
- IDEA第五章----Git常用技能
前几篇已经介绍了idea的环境搭建及基础配置常用模板等,这一章我们介绍下idea中git的一些常用技能,包括提交文件,排除提交文件,合并分支,解决冲突,还原代码等等等. 第一节:Git常用技能 Git ...
- EzHttp 流传输调用代码示例
EzHttp框架提供的内置接口,用于文件流等传输 流传输调用代码示例 内置接口: public interface IEzStreamHandler { Task<byte[]> GetD ...
- 树型权限管理插件:jQuery Tree Multiselect详细使用指南
1.认识jQuery Tree Multiselect 这个插件允许用户以树型的形式来呈现列表复选框的选择.多用于权限管理中用于分配不同的权限.使用文档,请参考: https://github ...
- .NET的JSON格式数据的三种转换方式
说明: 1..Net进行JSON格式的数据传递的时候,势必用到序列化和反序列化对象,总共有三种方式可是在.NET中实现序列化和反序列化的需求. 2.操作JSON的速度是:Json.net > M ...