JSONP不支持循环调用

问题描述

  在jquery或zepto下,循环调用同一个jsonp

  

 for(var i = 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);
            }
        });
    }

  结果

  有些成功有些失败了?这是为何?

问题解释

  观察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[0], xhr, options, deferred)
            }

            //回调函数
            window[callbackName] = originalCallback
            if (responseData && $.isFunction(originalCallback))
                originalCallback(responseData[0])

            //清空闭包引用的变量值,不清空,需闭包释放,父函数才能释放。清空,父函数可以直接释放
            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 > 0) 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 = 0;i<5;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);*/
        }
时间: 2024-08-13 02:05:14

JSONP不支持循环调用的相关文章

Python函数的循环调用

1 def foo (): 2 print 'runing foo' 3 bar () 4 5 def bar (): 6 print 'runing bar' 7 foo () 8 9 bar() 直接上脚本,上面的脚本如果换成C语言代码的话,foo函数前面肯定是要加一个bar函数的声明的,但是在Python中不需要,因为foo函数在未被调用前,不会判断bar函数是否合法,等到bar函数被调用的时候,bar函数已经被声明了,所以能找到. 因此Python也是支持循环调用的,A call B,

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

lua序列化 支持key类型为string, number 支持value类型为string, number, table 支持循环引用 支持加密序列化 支持loadstring反序列化 使用示例 local t = { a = 1, b = 2} local g = { c = 3, d = 4, t} t.rt = g local ser_str = ser(g) local unser_table = loadstring(sered)() 原理详解 采用递归序列化表的方式实现,并且支持循

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

在某些情况下,我们需要在WebAPI项目中添加对jsonP的支持.比如我们同时创建了MVC.Net和WebAPI两个项目,这两个项目使用不同的端口,这时如果MVC.Net项目的前端想要直接访问WebAPI项目,就会出现"cross-origin"的错误.要解决这个问题,我们通常会使用jsonP的方法. 要让WebAPI支持返回jsonP格式,需要的步骤如下: 1. 通过NuGet安装WebApiContrib.Formatting.Jsonp.项目地址:https://github.c

AWK中for循环调用数组解释

以前对于awk中的for循环调用数组一直不是很清晰,通过这个例子你将会对这种方法非常明白. #!/bin/sh echo"" | awk ' BEGIN { a[1]="123" a[2]="456" a[3]="789" } END{ for(i in a) { print i,a[i] } }' 结果:

循环调用spring的dao,数个过后无响应

循环调用spring的dao,数个过后无响应 博客分类: spring daospringssh 最近遇到这么一个问题:前台按钮发送AJax请求到后台,后台是SSH框架.每点击一下按钮就发送一次请求. 点击数次(7次)过后,页面无ajax响应. 在排除前台因素之后,找 到后台代码.写一个Test类. public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationCo

支持循环事件的日历日程控件MindFusion.Scheduling for WPF

MindFusion.Scheduling for WPF 是一款WPF平台下灵巧的日历日程控件,可以进行日程安排,计划调度,工作安排等,支持多种视图,多种外观样式,可以很轻松地整合到应用程序中,为项目开发节约了成本,缩短了开发时间. 具体功能: 软件的再分配完全免费 强命名的程序集 数字签名 购买的版本带有源代码 以C#写成 控件 能定义自定义类型的事件 支持循环事件 支持数据库的序列化 能存留于二进制流以及XML文档里 浏览 时间表浏览 列表浏览 日范围浏览 月份浏览 周范围浏览 月范围浏览

OC类的继承以及类的循环调用

一, 关于OC的实例变量的可见度,即实例变量的访问权限有三种: 1),@public           公有的 被@public修饰的实例变量是公共的,即没有访问权限,在任何文件中都可以访问,(访问方式是通过对象+指向操作符) 2),@protected    受保护的 被@protected修饰的实例变量有一定的访问限,只允许在本类文件及子类文件中访问,其他文件不可访问 3),@private         私有的 被@private 修饰的实例变量,只允在在本类文件中访问,不可以在子类文

织梦 dedecms 中LOOP 万能标签循环 调用 arcurl标签(获取链接)

在DEDECMSV5.3中,提供了loop万能循环标签,但是此循环标签只能循环出该表中的字段,而“[field:arcurl/]”链接标签并不能被解析出来,而DEDECMS官方论坛上也没有找到相关的解决办法,所以只有自己动手写代码了! 这是官方提供的代码:{dede:loop table='dede_archives' sort='' row='4' if=''}<a href='[field:arcurl/]'>[field:title/]</a>{/dede:loop}以下是我

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

ITOO V1.0的开发算是告一段落了,现在是整理总结交接环节,在这个项目中常见的问题也该好好整理一下和大家分享了,这次主要介绍转json循环调用的问题. 一.问题背景 相信只要使用ORM映射实体关联关系,实体中存在双向关联的都遇到过这样的问题: 其实这个问题在上次的.NET项目中遇到过,所以这个问题是一个常见问题,只不过因为这次实在java中第一次遇到,但是循环调用的原理还是没有改变的. 二.解决方案 由于刚java项目的经验不丰富,之前实体关系也没有这次项目中的复杂,所以没有解决过,不过学会