写一个 JSONP 请求函数

重复轮子,当练手,用时大概20分钟,希望下次更快些。

/**
 * 利用动态加载脚本来获取跨域的数据。支持:
 * 回调函数
 * 超时检测
 * 自动 GC
 */
$$.jsonp = $$.define($$.event, function(){
	/**
	 * @cfg {String} url
	 * @cfg {Function} callBack
	 * @cfg {String} callBackField
	 * @cfg {Object} params
	 */	
	this.init = function(cfg){
		var globalMethod_Token	= 'globalMethod_' + getRandom(),
			globalMethod		= '$$.jsonp.' + globalMethod_Token;
		
		var callBack = cfg.callBack;
		if(!callBack) throw '必须提供回调函数!';
			
		$$.jsonp[globalMethod_Token] = callBack.after(gc.bind(this), true); // 获取回调的引用,不管在哪个闭包中
		
		var callBackField	= cfg.callBackField || 'callBack',// 默认值
			url				= cfg.url,
			params			= cfg.params;
			
		params[callBackField] = globalMethod; // 加载 callBackField 字段到请求参数
		
		if(url && url.indexOf('?') != -1){
			throw 'url不能包含查询号?。';
		}else{
			url += json2urlParam(params);
		}
			
	    
		this.script = request(url);

		this.timeoutId = window.setTimeout(function(){
			// gc?
	        if(this.isSuccess == true){
	        }else{
				throw('[jsonp]超时!');
	        }
	    }.bind(this), this.timeout);
	}
	
	/**
	 * @param {Object} json
	 * @return {String}
	 */
	function json2urlParam(json){
		var tempArr = [];
		for(var i in json){
			tempArr.push(i + '=' + json[i]);
		}
		return '?' + tempArr.join('&');
	}
	
	function getRandom(){
		return parseInt(Math.random()*(200000-10000 + 1) + 10000); 
	}
	
	/**
	 * 发起请求
	 * 创建 script tag,并建立 head tag 缓存。
	 * @return {ScriptTag}
	 */
	function request(url){
		var script = document.createElement('script');
		
		script.type = 'text/javascript';
		script.src = url;

		if($$.jsonp.headTag === null){
			$$.jsonp.headTag = document.getElementsByTagName('head')[0];
		}
		$$.jsonp.headTag.appendChild(script);
		
		return script;
	}
	
	/**
	 * 移除 tag 标签及其事件hanlder
	 * 标记实例 ok token
	 * 如定时器有效,则取消之。
	 */
	function gc(){
		try{
			this.isSuccess = true;
			$$.jsonp.headTag.removeChild(this.script);
			
			if(this.timeoutId){
				window.clearTimeout(this.timeoutId);
			}
			console.log('[JSONP]gc OK!');
			
			return true;
		}catch(e){
			alert('[JSONP]gc fails!');
		}
	}
	
	this.isSuccess = false;
	this.timeout = 2000;
});

2012-12-28 补充一个 XHR 的,写了三十分钟:

$$.xhr = $$.define($$.event, function(){
	var defaultCfg = {
		httpMethod : 'GET',
		timeout	: 2000,
		isAsync	: true, // ff 必须输入 Boolean,ie则没那么严格。
		url : ''
	};
	this.init = function(cfg){
		this.xhr;
		this.xhrs = []; // 对象池
		
		this.on('load', onLoad);
		
		this.cfg = Object.create(defaultCfg);
		for (var i in cfg){
			this.cfg[i] = cfg[i];
		}
		this.cfg.httpMethod = this.cfg.httpMethod.toUpperCase(); // 强制大写
		
		checkURL_CallBack(this.cfg);

		this.onreadystatechange = onreadystatechange.delegate(null, this);
	}
	function onLoad(xhr){
		this.cfg.callBack(xhr.xhr.responseText);
	}
	
	function checkURL_CallBack(cfg){
		if(!cfg.url){
			throw '[request]未指定服务端地址';
		}else if(cfg.isAsync === false && !cfg.callBack){
			throw '[request]未指定回调函数';
		}else if(cfg.isAsync === false && typeof cfg.callBack != 'function'){
			throw '[request]指定回调函数参数其类型不是函数!';
		}
		
		if(cfg.onError && typeof cfg.onError != 'function'){
			throw '[request]指定失败的回调函数参数其类型不是函数!';
		}
	}
	
	function onreadystatechange(_XMLHttpRequestProgressEvent, xhrInstance) {
		var xhr = this; // 当前scope 就是 那个 XHR 对象。
		if(xhr.readyState == 4) {
			xhrInstance.fire('load', xhrInstance);
			// 结束 xhr
			xhr = null;
		}
	}
	this.request = function(){
		var cfg = this.cfg;
		var url = cfg.httpMethod == 'POST' ? cfg.url : cfg.url + json2urlParam(cfg.params);
		var xhr;
		xhr = new XMLHttpRequest();
		xhr.open(cfg.httpMethod, url, cfg.isAysc);
		xhr.onreadystatechange = this.onreadystatechange;// 为协调 ie,将 onreadystatechange 置于 open() 后。
		
		// 设置 HTTP 头
        cfg.httpMethod == 'POST' && xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        cfg.referer && xhr.setRequestHeader("Referer", cfg.referer);
        cfg.contentType && xhr.setRequestHeader("Content-Type", cfg.contentType); // you may set xhr.setRequestHeader("Accept", "text/json");

		
		this.xhr = xhr;
		this.xhrs.push({
			xhr : xhr,
			configSnapShot : Object.create(cfg) // 快照
		});
		
		xhr.send(cfg.httpMethod == 'POST' ? json2urlParam(cfg.params, true) : null);
	}
	/**
	 * @param {Object} json
	 * @return {String}
	 */
	function json2urlParam(json, isNoQuerySigne){
		if(!json){
			return '';
		}
		var tempArr = [];
		for(var i in json){
			tempArr.push(i + '=' + json[i]);
		}
		return isNoQuerySigne ? tempArr.join('&') : '?' + tempArr.join('&');
	}
});


©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页