注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

①嗰亽挺ぬ

莈亽噯,僦洎巳噯洎巳

 
 
 

日志

 
 
 
 

Javascript Callback的两种实现方案  

2013-08-05 23:56:05|  分类: web开发~js |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

下文主要比较两种现有的Javascript callback实现机制,暂且定为简单版和完整版,简单版的实现只有几行代码,但是无法捕获错误响应,完整版的代码多一些确可以实现错误捕获,而且可以使用的更方便。

简单版

简单版的实现大致如下:

  1. var head = document.getElementsByTagName('head')[0];  
  2. var script = document.createElement('script');  
  3. /*onreadystatechange在IE下使用,onload在其他浏览器下使用*/  
  4. script.onload = script.onreadystatechange = function(){  
  5.     if( !script.readyState || (script.readyState && script.readyState == 'loaded'){  
  6.         //TODO  
  7.     }  
  8. }  
  9. head.appendChild(script);  

短短几行代码已经能满足基本的需求了,而且兼容性还很不错。不过无法提供出错处理,而且使用起来不方便。

完整版

具体的说明都注释在代码中,请看注释。

IE

  1. function loadIECallback(param){  
  2.     param = initParam(param);  
  3.     /*清除,防止内存泄露*/  
  4.     function clear(){  
  5.         frag = script = script.onreadystatechange = frag[param.name] = null;  
  6.     }  
  7.     var charset = param.charset || 'gb2312';  
  8.     /*创建一个DocumentFragment充当script元素的父容器,这样的好处是不需要将节点真正的加入到DOM树中*/  
  9.     var frag = document.createDocumentFragment(), script = document.createElement('script');  
  10.     script.charset = charset;  
  11.     /*将callback函数定义在DocumentFragment上,script返回后可以直接调用到该函数*/  
  12.     frag[param.name] = function () {  
  13.         /*调用用户传入的callback*/  
  14.         param.success && param.success.apply(null, arguments);  
  15.         /*使用完成后清除垃圾信息*/  
  16.         clear();  
  17.     };  
  18.     /*注册script的onreadystatechange事件 
  19.      *一般情况,IE6下script的readyState会经历loading、interactive和loaded, 
  20.      *IE7下没有interactive(表示加载的数据虽然未完成但已经可以使用)状态, 
  21.      *而在interactive(IE7下则是loading之后和loaded之前)状态后请求的callback数据其实已经到达并可用 
  22.      *也就是说如果正常请求到数据,则在loaded状态前定义在DocumentFragment上的Callback就会被执行。 
  23.      *由于加载成功后onreadystatechange事件会被清空,因此一旦readyState到达了loaded状态则表示加载错误。 
  24.      */  
  25.     script.onreadystatechange = function () {  
  26.         if (script.readyState == 'loaded') {  
  27.             param.error && param.error();  
  28.             clear();  
  29.         }  
  30.     };  
  31.     script.src = param.url;  
  32.     frag.appendChild(script);  
  33. }  

其他浏览器

  1. function loadOther(param){  
  2.     param = initParam(param);  
  3.     /*清除,防止内存泄露*/  
  4.     function clear(){  
  5.         iframe.callback = iframe.errorcallback = null;  
  6.         iframe.src = 'about:blank', iframe.parentNode.removeChild(iframe), iframe = null;  
  7.     }  
  8.     var charset = param.charset || 'gb2312';  
  9.     /*采用iframe可以对错误进行响应*/  
  10.     var iframe = document.createElement('iframe');  
  11.     iframe.style.display = 'none';  
  12.   
  13.     /*在iframe的frameElement上定义callback*/  
  14.     iframe.callback = function () {  
  15.         param.success && param.success.apply(null, arguments);  
  16.         clear();  
  17.     };  
  18.     iframe.errorcallback = function () {  
  19.         param.error && param.error();  
  20.         clear();  
  21.     };  
  22.     try {  
  23.         document.body.appendChild(iframe);  
  24.         var doc = iframe.contentWindow.document;  
  25.         doc.open();  
  26.         doc.write(  
  27.             /*在iframe内容中定义真是的callback函数,以供正确请求到数据后进行响应,如果正确地请求到数据则会执行success回调并删除对错误的响应函数*/  
  28.             '<script type="text\/javascript">function ' + param.name + '() { window.frameElement.callback.apply(null, arguments); }</script>'  
  29.             /*写入script标签请求数据*/  
  30.             + '<script type="text\/javascript" src="' + param.url + '" charset="' + charset + '"></script>'  
  31.             /*如果没有请求道正确的数据,则会顺利执行完下面的脚步片段,对错误进行响应*/  
  32.             + '<script type="text\/javascript">window.setTimeout("try { window.frameElement.errorcallback(); } catch (exp) {}", 1)</script>'  
  33.         );  
  34.         doc.close();  
  35.     } catch (exp) {}  
  36. }  

使用实例

最简洁的方式如下,这里省略了name和key,那么实际上在实现时会自动生成一个带时间戳的callback name,并且默认key为callback,因此最后请求的URL应该为:
http://youa.baidu.com/suggest/se/s?cmd=suggest&type=kwd&max_count=10&keyword=xxx&callback=_callback_func_123123112。

  1. Connection.loadCallback({  
  2.     url: 'http://youa.baidu.com/suggest/se/s?cmd=suggest&type=kwd&max_count=10&keyword=' + keyword,  
  3.     success: successHandle1,  
  4.     error: errorHandle  
  5. });  

此外,如果返回的callback函数名是写死的,则需要指定该callback的名字,即参数中的name,使用方式如下:

  1. Connection.loadCallback({  
  2.     name: 'JSCallback',  
  3.     url: 'http://youa.baidu.com/suggest/se/s?cmd=suggest&type=kwd&max_count=10&keyword=' + keyword,  
  4.     success: successHandle1,  
  5.     error: errorHandle  
  6. });  

此外,如果返回的callback函数名是通过传参来指定的,则可以通过name和key来配置,其中name是callback函数名,key则是传参过程中的参数名,使用方式如下:

  1. Connection.loadCallback({  
  2.     name: 'JSCallback',  
  3.     key: 'cb',  
  4.     url: 'http://youa.baidu.com/suggest/se/s?cmd=suggest&type=kwd&max_count=10&keyword=' + keyword,  
  5.     success: successHandle1,  
  6.     error: errorHandle  
  7. });  

上例中,发出的请求URL应该类似:http://youa.baidu.com/suggest/se/s?cmd=suggest&type=kwd&max_count=10&keyword=&cb=JSCallback

具体的例子请看这里

总结一下

  1. 在IE的实现方案中,将DocumentFragment充当script元素的父容器,并且将用户定义的callback函数定义在DocumentFragment上,这样的好处是不需要将节点真正的加入到DOM树中即可完成callback功能。
  2. 在IE的实现方案中,利用script在readyState为loaded之前就已经可以做交互的原理实现了出错处理,如果请求正确则在readyState转变为loaded之前就应经完成响应,并删除script,所以如果readyState转变到loaded则视为error。
  3. 在IE之外的实现方案中,利用iframe实现了出错处理,脚本是顺序执行的,正确的响应执行后便销毁iframe,这样便没有机会执行后面的出错响应,只有当请求出错时方会执行。
  评论这张
 
阅读(3)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017