Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

跨域的异步请求三

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

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

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

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

        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('&');
	}
}

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(2574)  评论(1编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示