zoukankan      html  css  js  c++  java
  • 跨域的异步请求三

    这部分我们继续增强我们的系统,如强制定的回调函数。参考一些类库,这些回调函数暂定如下几种:

    • onStart:请求开始时调用。
    • onSuccess:请求成功时调用,通常后台会返回一个JSON给它做参数。
    • onTimeout:请求超时时调用,有一个参数,标识其耗时多少毫秒。
    • onError:请求失败时调用,有一个异常对象做参数。如果超时,我们会自动抛出一个自定义错误。
    • onComplete:请求完成时调用,为了保证它只执行一次,我们会对它进行包装。

    我们需要一些工具函数来完成这个系统,如类型判定,深拷贝,迭代器等。这些我以前在博客也讲过了,不详述了!

      var dom = {
            is:function (obj,type) {
              return (type === "Null" && obj === null) ||
                (type === "Undefined" && obj === void 0 ) ||
                Object.prototype.toString.call(obj).slice(8,-1) === type;
            },
            noop:function(){},
            deepcopy:function(result, source){
              for(var key in source) {
                var copy = source[key];
                if(result === copy) continue;//如window.window === window,会陷入死循环,需要处理一下
                if(dom.is(copy,"Object")){
                  result[key] = arguments.callee(result[key] || {}, copy);
                }else if(dom.is(copy,"Array")){
                  result[key] = arguments.callee(result[key] || [], copy);
                }else{
                  result[key] = copy;
                }
              }
              return result;
            },
            each : function(obj,fn,bind){
              for(var i in obj){
                if(obj.hasOwnProperty(i)){
                  if(fn.call(bind || obj[i],obj[i],i,obj)===false){
                    break
                  }
                }
              }
            },
            toQueryString : function (obj) {//将对象转换为查询字符串
              var enc = encodeURIComponent,
              pairs = [],
              regexp = /%20/g,
              backstop = {};
              dom.each(obj,function(value,name){
                if(value != backstop[name]){
                  var assign = enc(name).replace(regexp,'+') + "=";
                  if(dom.is(value,"Array")){
                    dom.each(value,function(el){
                      pairs.push(assign + enc(el).replace(regexp,'+'));
                    });
                  }else{
                    pairs.push(assign + enc(value).replace(regexp,'+'));
                  }
                }
              });
              return pairs.join("&"); // String
            },
        
        head:document.getElementsByTagName("head")[0],
            //obj的成员有url,callbackName,callback,data,cache
            jsonp:function(){}
     }
    

    然后是系统的主体部分了:

            dom.jsonp = function(obj){
              var self = arguments.callee;
              //=============列队处理======================
              if (self.callbacks.length) {
                setTimeout(function() {self(obj)}, 0);
                return;
              }
              //=============配置对象处理===================
              obj = dom.deepcopy(dom.deepcopy({}, dom.jsonp.settings), obj);
      
            
              var query = dom.toQueryString(obj.data),
              url = obj.url+"?"+ query+"&"+obj.callbackName+"=dom.jsonp.callback",
              script = document.createElement("script"),
              timed_out = false, timeoutID = null,
              destroyScript = function(){
                script.parentNode && script.parentNode.removeChild( script );
              }, old = obj.onComplete;
              obj.startTime = new Date-0;
    
              obj.onComplete = function(){//修正onComplete回调%>
                if(!arguments.callee.done){
                  old.call(this,[].slice.call(arguments))
                  arguments.callee.done = true;
                }
              }
              //========构建新JS文件上的回调函数==================
              dom.jsonp.addCallback((function(obj){
                return function(){//参数未定,第一个参数肯定为JSON
    
                  var args = [].slice.call(arguments)
                  try{
                    if (!timed_out){//清除timeout引用
                      clearTimeout(timeoutID);
                    }else{
                      throw new Error(504,"Gateway Timeout")
                    }
                    obj.onSuccess.apply(obj,args);
                  }catch(e){
                    obj.onError.call(null,e);
                  }finally{
                    obj.onComplete.apply(obj,args);
                    destroyScript();
                  }
                }
              })(obj));
           //================设置script标签=============
           if(!obj.cache)
                url+= '×tamp='+(new Date-0)
              script.src = url;
              dom.head.appendChild(script);
    
              obj.onStart.call(obj,null);
              
              //===========设置请求超时的相关回调============
              if (obj.timeout){
                timeoutID = setTimeout(function(){
                  //如果超时则执行如下回调函数
                  timed_out = true;
                  var time = new Date  - obj.startTime;
                  obj.onTimeout.call(obj,time);
                  obj.onComplete.call(obj,null);
                  destroyScript();
                },obj.timeout)
              }
    
    
            };
    //静态成员
          dom.deepcopy(dom.jsonp, {
            settings : {
              url:location.href,
              callbackName: 'callback',
              cache:false,
              onStart:dom.noop,
              onSuccess:dom.noop,
              onComplete:dom.noop,
              onTimeout:dom.noop,
              onError:dom.noop
            },
            callbacks : [],
            callback :function(){//统一处理回调函数
              var objs = this.callbacks,
              args = [].slice.call(arguments)
              for (var i=0,el;el=objs[i++];) {
                el.apply(null,args)
              }
              this.callbacks = [];
            },
            addCallback : function(obj){
              this.callbacks.push(obj)
            }
          });
    

    例子中我们做了各种测试,都能过了,不过除IE外,其他浏览器的执行顺序都朋点絮乱了。这缘于标准浏览器并没有对setTimeout的待执行函数弄成一个队列,看来我们要自行搞一个延迟队列才行了……

    var JSONP = function JSONP(url, options) {
    	this.options = {callbackParamName: 'callback'};
    	for (var prop in options) this.options[prop] = options[prop];
    	this.options= options;
    	this.url = url;
    	this.head = document.getElementsByTagName('head')[0];
    
    	var _this = this;
    	this.request();
    	if (options.timeout) this.timer = setTimeout(function() {_this.timeoutHandler();}, options.timeout);
    }
    
    JSONP.sequence = 0;
    JSONP.prototype = {
    	constructor: JSONP,
    
    	request: function() {
    		var url;
    		var script = this.script = document.createElement('script');
    		var options = this.options;
    		var _this = this;
    		this.currentCallbackName = "callback_" + JSONP.sequence++;
    
    		var parameters = this.options.callbackParamName + '=JSONP.' + this.currentCallbackName + '&' + this.composeParams();
    
    		if (this.url.indexOf('?') > -1) url = this.url + '&' + parameters;
    		else url = this.url + '?' + parameters;
    
    		JSONP[this.currentCallbackName] = function(json) {
    			clearTimeout(_this.timer);
    			_this.head.removeChild(script);
    			delete JSONP[_this.currentCallbackName];
    			if (options.onSuccess) options.onSuccess.call(_this, json);
    		};
    		script.setAttribute('src', url);
    		script.setAttribute('type', 'text/javascript');
    		this.head.appendChild(script);
    	},
    
    	timeoutHandler: function() {
    		if (JSONP[this.currentCallbackName]) {
    			JSONP[this.currentCallbackName] = this.nop;
    			this.head.removeChild(this.script);
    		}
    		this.options.onFailure();
    	},
    
    	nop: function() {
    	},
    
    	composeParams: function() {
    		var ret = '';
    		var params = this.options.params;
    		var tmpArray = [];
    		for (var key in params) {
    			tmpArray.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
    		}
    		return tmpArray.join('&');
    	}
    }
    
  • 相关阅读:
    常用linux命令及其设置
    shell脚本编写步骤及其常用命令和符号
    浏览器访问php脚本通过sendmail用mail函数发送邮件
    windows server 定期备份数据库脚本
    图片垂直水平居中
    "!function",自执行函数表达式
    jQuery(function(){})与(function(){})(jQuery) 的区别
    在Windows Server 2019通过Docker Compose部署Asp.Net Core
    Redis集群同步问题
    webapi跨域使用session
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1744685.html
Copyright © 2011-2022 走看看