跨域的异步请求三
这部分我们继续增强我们的系统,如强制定的回调函数。参考一些类库,这些回调函数暂定如下几种:
- onStart:请求开始时调用。
- onSuccess:请求成功时调用,通常后台会返回一个JSON给它做参数。
- onTimeout:请求超时时调用,有一个参数,标识其耗时多少毫秒。
- onError:请求失败时调用,有一个异常对象做参数。如果超时,我们会自动抛出一个自定义错误。
- onComplete:请求完成时调用,为了保证它只执行一次,我们会对它进行包装。
我们需要一些工具函数来完成这个系统,如类型判定,深拷贝,迭代器等。这些我以前在博客也讲过了,不详述了!
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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的待执行函数弄成一个队列,看来我们要自行搞一个延迟队列才行了……
如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码


机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述