重复轮子,当练手,用时大概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('&'); } });