zoukankan      html  css  js  c++  java
  • jsonp封装方法二

    前言: 看到玉伯的聊聊jsonp的p,引发了另一种loader方式来跨域的方法,他把它叫做JSONM协议,原理和seajs相似,都是动态加载script,加载完成后执行callback,

    同时还不用考虑回调函数名,都指定为define,服务端可以静态存储例如(define({name:"alice",age:21}))。如果数据是静态的,还可以放在cdn上。原文issue连接

    以及一篇原理分析,写得很赞 连接

    所以我就斗胆按照自己的理解,自己写了一个简易的用loader的思想来完成jsonp。

    原理概述:动态加载script,利用onload事件执行回调函数,在ie9/10中 用onreadystatechange。可是在ie6-8中不支持,在seajs里看到了绝招,利用readyState为interactive判断正在执行的脚本,脚本的src和传入时的callback建立唯一连接,进行查找,执行回调函数。

    那么怎么获取json数据呢? 我用JSONPData这个里存储获取到的_jsondata(私有变量,提供接口访问)。在非ie中就简单了,直接callback.call(this,JSONPData.getJsonData()).

    我实现的这个有什么限制呢? 

    在ie6-8中,因为用的是src和callback唯一对应,假若几个请求的src相同,callback只能得到第一次设置的函数,解决方法,如果回调函数不同,就用不同的src请求喽,加个无意义的参数就ok啦。

     var currentAddingScript;
     var JSONP = (function() {
         var _head = document.getElementsByTagName("head")[0];
         var _baseElement = document.getElementsByTagName("base")[0];
         var _helper = {
             encodeURL: function(url) {
                 var param = url.split("?")[1];
                 var url = url.split("?")[0];
                 var params = param.split("&");
                 var parLen = params.length;
    
                 for (var i = 0; i < parLen; i++) {
                     var paItem = params[i].split("=");
                     url += url.indexOf("?") >= 0 ? "&" : "?";
                     url += encodeURIComponent(paItem[0]) + "=" + encodeURIComponent(paItem[1]);
                 }
                 return url;
             },
             addLoad: function(node, callback) {
                 node.onload = node.readystatechange = function() {
                     // Ensure only run once  in IE9
                     node.onload = node.readystatechange = null;
                     if (!this.readyState || node.readyState == "complete" || node.readyState == "loaded") {
                         callback.call(this, JSONPData.getJsonData());
                         this.parentNode.removeChild(this);
                     }
                 }
             }
         };
         return {
             start: function(url, func) {
                 var encUrl = url;//存储的是未经过编码的,以便与对应的callback创建关联
                 //创建script结点
                 var script = document.createElement("script");
                 if (encUrl.indexOf("?") >= 0) {
                     url = encUrl + "&callback=JSONP.callback";
                     script.src = _helper.encodeURL(url);
                 } else {
                     url = encUrl + "?callback=JSONP.callback";
                     script.src = _helper.encodeURL(url);
                 }
                 script.charset = "UTF-8";
    
                 //绑定加载完成事件
                 _helper.addLoad(script, func);
    
                 // For some cache cases in IE 6-8, the script executes IMMEDIATELY after
                 // the end of the insert execution, so use `currentlyAddingScript` to
                 // hold current node,
                 currentAddingScript = script;
                 _baseElement ? _head.insertBefore(script, _baseElement) : _head.appendChild(script);
    
                 //for ie6-9 关联script 和callback           
                 var data = {};
                 data[url] = func;
                 JSONPData.save(data);
             },
             getInteractiveScript: function() {
                 //ie6-9  获取正在执行的脚本
    
                 if (currentAddingScript) {
                     return currentAddingScript;
                 }
                 var scripts = document.getElementsByTagName('script');
                 for (var i = 0; i < scripts.length; i++) {
                     var script = scripts[i];
                     if (script.readyState === 'interactive') {
                         return script;
                     }
                 }
                 return null;
             },
             callback: function(data) {
    
                 // if ie6-9
                 if (document.attachEvent) {
                     var script = JSONP.getInteractiveScript();
                     var callback = null;
                     if (script) {
                         callback = JSONPData.findCallback(script.src);
                         if (typeof callback == "function") {
                             callback(data);
                         }
                     } else {
                         console.log("fail");
                     }
                 }
                 // 设置返回的json数据,供调用
                 JSONPData.setJsonData(data);
             }
         }
     })();
    
     var JSONPData = (function() {
         var _dataStorage = [];
         var _jsonData;
    
         // 每个数据项是data {url: [callbackFunc]}
         return {
             save: function(data) {
                 //检查data的url若相同,则回调函数不变
                 for (var i in data) {
                     if (!_dataStorage.hasOwnProperty(i)) {
                         _dataStorage.push(data);
                     }
                 }
             },
             findCallback: function(url) {
                 var len = _dataStorage.length;
                 for (var i = 0; i < len; i++) {
                     if (_dataStorage[i][url]) {
                         return _dataStorage[i][url];
                     }
                 }
                 return null;
             },
             setJsonData: function(data) {
                 _jsonData = data ? data : null;
             },
             getJsonData: function() {
                 return _jsonData;
             }
         }
     })();

     update分割线

    ==========================================================================================

    我用Ie的仿真模式,测试ie7和ie8时,发现第一次点击按钮触发请求不能返回数据,请先看重要的html部分

    <button id="button">发送三个jsonp请求</button>
    

    绑定button点击事件

       var button = document.getElementById("button");
        button.onclick = function() {
            JSONP.start("http://localhost:8088/data.php", function(data) {
                console.log(data);
                console.log("yes1");
            });
            JSONP.start("http://localhost:8088/data.php?cc=ff", function(data) {
                console.log(data);
                console.log("yes2");
            });
            JSONP.start("http://localhost:8088/data.php?ur=f", function(data) {
                console.log(data);
                console.log("yes3");
            });
        }
    

    在ie7,8下我点一下后不出现结果,

    通过断点调试,代码问题出在了这段上,我先把创建的script结点添加到dom结点中,之后再存储url和callback,导致在立即执行函数时,数据还未存储,无法找到关联的callback,所以没有成功调用,解决方案是,存储数据放在插入节点之前,就完美啦!

     再看运行结果:

     

    新代码:就只贴了需要做小改动得JSONP返回的start函数代码:

     start: function(url, func) {
                    var encUrl = url;
    
                    //创建script结点
                    var script = document.createElement("script");
                    if (encUrl.indexOf("?") >= 0) {
                        url = encUrl + "&callback=JSONP.callback";
                        script.src = _helper.encodeURL(url);
                    } else {
                        url = encUrl + "?callback=JSONP.callback";
                        script.src = _helper.encodeURL(url);
                    }
                    script.charset = "UTF-8";
    
                    //for ie6-9 关联script 和callback     
                    var data = {};
                    data[url] = func;
                    JSONPData.save(data);
                     
                    //绑定加载完成事件
                    _helper.addLoad(script, func);
    
                    // For some cache cases in IE 6-8, the script executes IMMEDIATELY after
                    // the end of the insert execution, so use `currentlyAddingScript` to
                    // hold current node,
                    currentAddingScript = script;
                    _baseElement ? _head.insertBefore(script, _baseElement) : _head.appendChild(script);     
                }, 
    

      

  • 相关阅读:
    Boost Started on Windows
    7-Zip
    代码的命名规则
    基础扫盲:YEAR关键字 IN操作符
    基础扫盲:INSERT INTO 和 SELECT 结合使用
    知识盲点:存在外键的的表,在插入数据时应该如何操作?
    SQL Identity函数
    SQL 中DateName()函数及DatePart()函数
    OS开发多线程篇—GCD介绍
    经典SQL语句大全
  • 原文地址:https://www.cnblogs.com/AliceX-J/p/5896646.html
Copyright © 2011-2022 走看看