zoukankan      html  css  js  c++  java
  • 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);*/
            }
  • 相关阅读:
    python爬虫之requests库
    python爬虫之urllib库
    fiddler配置及使用教程
    react中受控组件相关的warning
    Sublime Text 自动生成文件头部注释(版权信息):FileHeader 插件的使用
    手动安装sublime插件babel-sublime
    自定义组件 点击空白处隐藏
    pagination分页(支持首页,末页,跳转)
    vue打包以后,除了首页意外,其余页面是空白
    pm2踩过的坑
  • 原文地址:https://www.cnblogs.com/mominger/p/4459712.html
Copyright © 2011-2022 走看看