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映射实体关联 ...
随机推荐
- MySQL用户认证及权限grant-revoke
一.MySQL用户认证: 登录并不属于访问控制机制,而属于用户身份识别和认证: 1.用户名-user 2.密码-password 3.登录mysqld主机-host 实现用户登录MySQL,建立连接. ...
- javascript继承详解(待续)
常见继承分两种,一种接口继承,继承方法签名:一种实现继承,继承实际方法.js只支持后一种. 1原型链 首先看原型.构造函数.实例的关系.如果我们让一个函数的原型对象等于另一个的实例,然后另一个的原型对 ...
- php 启动过程 - reqeust RINIT 过程
php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...
- NuGet(Nuget Packages)
Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展.在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加.移除和更新引 ...
- java 并发工具类CountDownLatch & CyclicBarrier
一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...
- linux中移动光标
ctrl + e 光标 移动到 行尾 ctrl + a 光标 移动到 行首
- get和post提交数据的区别
get是客户端向服务器索取数据的请求,设定的初衷是,客户端(浏览器)给服务器发送请求,然后服务器再返回给客户端其要求的数据. 那么为什么说get也能提交数据呢? 我们仔细理解第一句话“客户端(浏览器) ...
- 罪恶的SEO优化
1. 基础概念开始 SEO,搜索引擎优化.概括来说就是针对分析搜索引擎的网站收录以及评价规律,来对网站的结构,内容以及其他因素作出一些合理调整,使得网站更容易被搜索引擎收录,并且能够尽量排在搜索引擎自 ...
- 玩转spring boot——ajax跨域
前言 java语言在多数时,会作为一个后端语言,为前端的php,node.js等提供API接口.前端通过ajax请求去调用java的API服务.今天以node.js为例,介绍两种跨域方式:Cross ...
- webstorm html碎片整理功能
我们用字符串形式写html模板时,或者向某标签添加html内容时,如下,如果这个str更加的长,一旦里面少了一个单引号,少了一个加号,基本报错还看不懂,一脸懵逼... // 假定后台传给我们的数据为 ...