问题描述

  在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不支持循环调用的更多相关文章

  1. Python函数的循环调用

    def foo (): print 'runing foo' bar () def bar (): print 'runing bar' foo () bar() 直接上脚本,上面的脚本如果换成C语言 ...

  2. jsonp 跨域只能调用一次ajax(无法多次调用或者循环调用)

    jsonp 跨域只能掉用一次ajax(无法多次调用或者循环调用) 百度搜索关键字:jsonp 只能调用一次ajax 解决方法 //回调函数设置,给后台执行        window[callback ...

  3. lua序列化(支持循环引用)

    lua序列化 支持key类型为string, number 支持value类型为string, number, table, boolean 支持循环引用 支持加密序列化 支持loadstring反序 ...

  4. MVC.Net:WebAPI添加对jsonP的支持

    在某些情况下,我们需要在WebAPI项目中添加对jsonP的支持.比如我们同时创建了MVC.Net和WebAPI两个项目,这两个项目使用不同的端口,这时如果MVC.Net项目的前端想要直接访问WebA ...

  5. 03server平台delphi程序不支持直接调用webservice

    经过多次测试和查证,发现03server平台用delphi7.0开发的应用程序就是不支持直接调用webservice,无论这个webservice是delphi开发的还是C#开发,抑或是java开发的 ...

  6. jmeter之regular expression extractor ,并循环调用匹配到的多个值

    jmeter之regular expression extractor 官方介绍:http://jmeter.apache.org/usermanual/regular_expressions.htm ...

  7. Oracle之带参存储过程(存储过程中for循环调用存储过程)

    --带参存储过程create or replace procedure testdate(v in number) is i number; begin i:=v; insert into test_ ...

  8. Sybase:循环调用存储过程

    Sybase:循环调用存储过程 一.日期循环 declare @c_count int declare @rq int --获取两个日期之间的天数 ,getdate()) begin ,),),),) ...

  9. 使用jackson转json解决双向关联循环调用

    ITOO V1.0的开发算是告一段落了,现在是整理总结交接环节,在这个项目中常见的问题也该好好整理一下和大家分享了,这次主要介绍转json循环调用的问题. 一.问题背景 相信只要使用ORM映射实体关联 ...

随机推荐

  1. 网站与域名知识扫盲-DNS

    域名概述 域名的概念 IP地址不易记忆 早期使用Hosts解析域名 主机名称重复 主机维护困难 DNS(Domain Name System 域名系统) 分布式 层次性 域名空间结构 根域 组织域[. ...

  2. 优化Servlet:(利用反射的思想)

    1.创建BaseServlet (重写父类的service方法) package com.learning.web.servlet; import java.io.IOException; impor ...

  3. 前端借助dom-to-image把HTML转成图片并通过ajax上传到服务器

    之前接到了一个任务,把jsp中的table转成一个图片,保存在指定文件夹并显示在前端. 我的思路是:一.引用第三方js在前端把table转成图片 二.通过ajax把图片上传到服务器,保存在指定文件夹 ...

  4. 4 安装MPush

    cnblogs-DOC 1.服务器环境 2.安装Redis3.安装Zookeeper4.安装MPush5.安装Alloc服务6.完整测试7.常见问题 一.Linux安装Mpush [root@loca ...

  5. Spring Boot启动过程(七):Connector初始化

    Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...

  6. AngularJS的过滤器$filter

    过滤器(filter)主要用于数据的格式上,通过某个规则,把值处理后返回结果.例如获得数据集,可排序后再返回. ng内置的共有九种过滤器: currency 货币 使用currency可以将数字格式化 ...

  7. androidStudio通过svn进行版本控制

    andoridStudio配置使用svn(以windows为例) 1.先安装svn客户端程序,TortoiseSVN,注意安装过程中要勾选command line client tools(默认是不安 ...

  8. 学习MVC之租房网站(六)-用户登录和权限控制

    在上一篇<学习MVC之租房网站(五)-权限.角色.用户管理>完成了权限.角色.用户的增删改查,现在将基于前面完成的内容,进行后台用户登录和权限控制功能的开发. 一.用户登录 用户登录涉及到 ...

  9. Spring数据库访问

    一般采用第三方具有连接缓冲池的数据源实现类:spring支持最常见的两个具有连接缓冲池的数据源为:DBCP和C3P0; DBCP(Database connection pool) 是Apache的一 ...

  10. JavaEE开发之SpringMVC中的自定义消息转换器与文件上传

    上篇博客我们详细的聊了<JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术>,本篇博客依然是JavaEE开发中的内容,我们就来聊一下SpringMVC中的自定义消息转发器 ...