导航栏: 首页 评论列表

前端MVC框架[02] 发送AJAX请求及建立连接池

默认分类 2012-10-11 07:51:28

  1. /  
  2.   异步请求管理器  
  3.  /  
  4. var Requester = {  
  5.     /  
  6.       全局事件处理接口 注:不支持onsuccess  
  7.        
  8.       @Map {'ontimeout':function(){},'onfailure':function(){}}  
  9.      /  
  10.     handler:{},  
  11.     /   
  12.       获取XMLHttpRequest对象   
  13.          
  14.       @return {XMLHttpRequest} XMLHttpRequest对象   
  15.       @description 使用缓存模式避免每次都检测浏览器类型  
  16.      */   
  17.     createXHRObject: function () {  
  18.         var me = this,  
  19.             i,  
  20.             list,  
  21.             len,  
  22.             xhr = null,  
  23.             methods = [  
  24.                 function () {return new XMLHttpRequest();},   
  25.                 function () {return new ActiveXObject('Msxml2.XMLHTTP');},  
  26.                 function () {return new ActiveXObject('Microsoft.XMLHTTP');}  
  27.             ];  
  28.           
  29.         for (i = 0, len = methods.length; i < len; i++) {  
  30.             try {  
  31.                 xhr = methodsi;  
  32.                 this.createXHRObject = methods[i];  
  33.                 break;  
  34.             } catch (e) {  
  35.                 continue;  
  36.             }  
  37.         }  
  38.         if (!xhr) {  
  39.             throw new Error(100000,'Requester.createXHRObject() fail. Your browser not support XHR.');  
  40.         }  
  41.           
  42.         xhr.eventHandlers = {};  
  43.         xhr.fire = me.creatFireHandler();  
  44.           
  45.         return xhr;  
  46.     },  
  47.                                       
  48.     /   
  49.       生成新的触发事件方法   
  50.          
  51.       @param {String} type 事件类型   
  52.      /   
  53.     creatFireHandler: function(){  
  54.         return function (type) {   
  55.             type = 'on' + type;   
  56.             var xhr = this,  
  57.                 handler = xhr.eventHandlers[type],   
  58.                 globelHandler = window.Requester.handler[type];   
  59.                
  60.             // 不对事件类型进行验证   
  61.             if (handler) {   
  62.                 if (xhr.tick) {   
  63.                   clearTimeout(tick);   
  64.                 }   
  65.                   
  66.                 if (type != 'onsuccess') {   
  67.                     handler(xhr);   
  68.                 } else {   
  69.                     //处理获取xhr.responseText导致出错的情况,比如请求图片地址.   
  70.                     try {   
  71.                         xhr.responseText;   
  72.                     } catch(error) {   
  73.                         return handler(xhr);   
  74.                     }   
  75.                     var text = xhr.responseText.replace(/^\s+/ig, "");   
  76.                     if(text.indexOf('{') === 0){   
  77.                         //{success:true,message:   
  78.                         //插入表单验证错误提示   
  79.                         var JSONParser;   
  80.                         try {   
  81.                             JSONParser = new Function("return " + text + ";");  
  82.                             data = JSONParser();    
  83.                         }   
  84.                         //如果json解析出错则尝试移除多于逗号再试   
  85.                         catch (e){   
  86.                             JSONParser = new Function("return " + window.Requester.removeJSONExtComma(text) + ";");   
  87.                             data = JSONParser();    
  88.                         }   
  89.                         if ( String(data.success).replace(/\s/ig,'').toLowerCase() !== 'true' ) {   
  90.                             // 当后端验证失败时  
  91.                             if (Requester.backendError) {  
  92.                                 Requester.backendError(data);  
  93.                             }  
  94.                         }   
  95.                            
  96.                         handler(data);   
  97.                     }else{   
  98.                         handler(text);   
  99.                     }   
  100.                 }   
  101.             }   
  102.             // 检查是否配置了全局事件  
  103.             else if (globelHandler) {   
  104.                 //onsuccess不支持全局事件   
  105.                 if (type == 'onsuccess') {   
  106.                     return;   
  107.                 }   
  108.                 globelHandler(xhr);   
  109.             }  
  110.         };  
  111.     },  
  112.     /  
  113.       检测是否有空闲的XHR或创建新对象  
  114.        
  115.       @after Requester  
  116.       @comment 使用Facade外观模式修改Requester.request方法  
  117.       以增加路径权限判断  
  118.      /  
  119.     getValidXHR: function () {  
  120.         var me = this;  
  121.         return me.createXHRObject();  
  122.     },  
  123.     /  
  124.       request发送请求  
  125.        
  126.       @url {String} 请求的URL  
  127.       @options {Map} POST的参数,回调函数,MD5加密等  
  128.      /   
  129.     request: function (url, opt_options) {  
  130.         var xhr = this.getValidXHR();  
  131.         //有可用连接  
  132.         if (xhr) {  
  133.             var me = this,  
  134.                 options     = opt_options || {},   
  135.                 data        = options.data || "",   
  136.                 async       = !(options.async === false),   
  137.                 username    = options.username || "",   
  138.                 password    = options.password || "",   
  139.                 method      = (options.method || "GET").toUpperCase(),   
  140.                 headers     = options.headers || {},   
  141.                 // 基本的逻辑来自lili同学提供的patch   
  142.                 timeout     = options.timeout || 0,   
  143.                 usemd5      = options.usemd5 || false,  
  144.                 tick, key, str,  
  145.                 stateChangeHandler = me.createStateChangeHandler();   
  146.            
  147.               
  148.             // 将options参数中的事件参数复制到eventHandlers对象中   
  149.             // 这里复制所有options的成员,eventHandlers有冗余   
  150.             // 但是不会产生任何影响,并且代码紧凑                
  151.             for (key in options) {   
  152.                 xhr.eventHandlers[key] = options[key];   
  153.             }   
  154.                
  155.             headers['X-Requested-With'] = 'XMLHttpRequest';   
  156.                
  157.                
  158.             try {   
  159.                 //提交到服务器端的参数是Map则转换为string  
  160.                 if(Object.prototype.toString.call(data)==='[object Object]'){   
  161.                     str = []   
  162.                     for(key in data){  
  163.                         if (key){  
  164.                             str.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))   
  165.                         }  
  166.                     }  
  167.                     data = str.join('&');  
  168.                 }  
  169.                   
  170.                 //使用GET方式提交  
  171.                 if (method == 'GET') {   
  172.                     if (data) {   
  173.                         url += (url.indexOf('?') >= 0 ? ( data.substr(0,1) == '&' ? '' : '&') : '?') + data;   
  174.                         data = null;   
  175.                     }  
  176.                 }  
  177.                 else if (usemd5) {  
  178.                     data = me.encodeMD5(data);  
  179.                 }  
  180.                   
  181.                 if (username) {   
  182.                     xhr.open(method, url, async, username, password);   
  183.                 } else {   
  184.                     xhr.open(method, url, async);   
  185.                 }   
  186.                   
  187.                 if (async) {   
  188.                     xhr.onreadystatechange = stateChangeHandler;   
  189.                 }   
  190.                    
  191.                 // 在open之后再进行http请求头设定   
  192.                 // FIXME 是否需要添加; charset=UTF-8呢   
  193.                 if (method == 'POST') {   
  194.                     xhr.setRequestHeader("Content-Type",   
  195.                         (headers['Content-Type'] || "application/x-www-form-urlencoded"));   
  196.                 }   
  197.                    
  198.                 for (key in headers) {   
  199.                     if (headers.hasOwnProperty(key)) {   
  200.                         xhr.setRequestHeader(key, headers[key]);   
  201.                     }   
  202.                 }   
  203.                    
  204.                 xhr.fire('beforerequest');   
  205.                   
  206.                 if (timeout) {   
  207.                   xhr.tick = setTimeout(function(){   
  208.                     xhr.onreadystatechange = window.Requester.fn;   
  209.                     xhr.abort();   
  210.                     xhr.fire("timeout");   
  211.                   }, timeout);   
  212.                 }   
  213.                 xhr.send(data);   
  214.                    
  215.                 if (!xhr.eventHandlers['async']) {   
  216.                     stateChangeHandler();   
  217.                 }   
  218.             } catch (ex) {   
  219.                 xhr.fire('failure');   
  220.             }   
  221.         }  
  222.         //暂时没有可用连接,将请求放进队列  
  223.         else {  
  224.             this.que.push({'url':url,'options':options});  
  225.         }  
  226.     },  
  227.     /   
  228.      * readyState发生变更时调用   
  229.      *    
  230.      * @ignore   
  231.      */   
  232.     createStateChangeHandler: function() {   
  233.         return function() {  
  234.             var xhr = this;  
  235.             if (xhr.readyState == 4) {   
  236.                 try {   
  237.                     var stat = xhr.status;   
  238.                 } catch (ex) {   
  239.                     // 在请求时,如果网络中断,Firefox会无法取得status   
  240.                     xhr.fire('failure');   
  241.                     return;   
  242.                 }   
  243.                    
  244.                 xhr.fire(stat);   
  245.                    
  246.                 // http://www.never-online.net/blog/article.asp?id=261   
  247.                     // case 12002: // Server timeout         
  248.                     // case 12029: // dropped connections   
  249.                     // case 12030: // dropped connections   
  250.                     // case 12031: // dropped connections   
  251.                     // case 12152: // closed by server   
  252.                     // case 13030: // status and statusText are unavailable   
  253.                    
  254.                 // IE error sometimes returns 1223 when it    
  255.                 // should be 204, so treat it as success   
  256.                 if ((stat >= 200 && stat < 300)   
  257.                     || stat == 304   
  258.                     || stat == 1223) {   
  259.                     xhr.fire('success');   
  260.                 } else {   
  261.                     xhr.fire('failure');   
  262.                 }   
  263.                    
  264.                 /*   
  265.                  * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the   
  266.                  * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler   
  267.                  * function maybe still be called after it is deleted. The theory is that the   
  268.                  * callback is cached somewhere. Setting it to null or an empty function does   
  269.                  * seem to work properly, though.   
  270.                  *    
  271.                  * On IE, there are two problems: Setting onreadystatechange to null (as   
  272.                  * opposed to an empty function) sometimes throws an exception. With   
  273.                  * particular (rare) versions of jscript.dll, setting onreadystatechange from   
  274.                  * within onreadystatechange causes a crash. Setting it from within a timeout   
  275.                  * fixes this bug (see issue 1610).   
  276.                  *    
  277.                  * End result: *always* set onreadystatechange to an empty function (never to   
  278.                  * null). Never set onreadystatechange from within onreadystatechange (always   
  279.                  * in a setTimeout()).   
  280.                  */   
  281.                 window.setTimeout(function() {   
  282.                     // 避免内存泄露.   
  283.                     // 由new Function改成不含此作用域链的 window.Requester.fn 函数,   
  284.                     // 以避免作用域链带来的隐性循环引用导致的IE下内存泄露. By rocy 2011-01-05 .   
  285.                     xhr.onreadystatechange = window.Requester.fn;   
  286.                     if (xhr.eventHandlers['async']) {   
  287.                         xhr = null;   
  288.                     }   
  289.                 }, 0);   
  290.                   
  291.                 window.Requester.checkQue();  
  292.             }   
  293.         }  
  294.     },  
  295.     /  
  296.       encodeMD5加密提交的数据  
  297.        
  298.       @data {String} 需要加密的paramString  
  299.       @return {String} 加密后的paramString  
  300.      /   
  301.     encodeMD5: function (data) {  
  302.         var paramstr = Base64.encode(data).replace(/\+/g,'*');  
  303.         var md5 = String(MD5.encode(paramstr)).toUpperCase();  
  304.         paramstr = paramstr.split('');  
  305.         paramstr.reverse();  
  306.           
  307.         return 'result=' + md5 + paramstr.join('');  
  308.     }  
  309. };  
  310.   
  311. window.Requester = Requester;  
  312. window.Requester.fn = function(){};  
  313.   
  314. /**  
  315.  * 移除JSON字符串中多余的逗号如{'a':[',],}',],}  
  316.  *  
  317.  * @param {string} JSON字符串  
  318.  * @return {string} 处理后的JSON字符串  
  319.  */  
  320. Requester.removeJSONExtComma = function(str) {  
  321.     var i,  
  322.         j,  
  323.         len,  
  324.         list,  
  325.         c,  
  326.         notValue = null,  
  327.         preQuot = null,  
  328.         lineNum;  
  329.   
  330.     list = String(str).split('');  
  331.     for (i = 0, len = list.length; i < len; i++) {  
  332.         c = list[i];  
  333.         //单引或双引  
  334.         if (/^[\'\"]$/.test(c)) {  
  335.             if (notValue === null && preQuot === null) {  
  336.                 notValue = false;  
  337.                 preQuot = i;  
  338.                 continue;  
  339.             }  
  340.             //值  
  341.             if (!notValue) {  
  342.                 //前面反斜杠个数  
  343.                 lineNum = 0;  
  344.                 for (j = i - 1; j > -1; j--) {  
  345.                     if (list[j] === '\\') {lineNum++;}  
  346.                     else { j = -1; }  
  347.                 }  
  348.                 //个数为偶数且和开始引号相同  
  349.                 //结束引号  
  350.                 if (lineNum % 2 === 0) {  
  351.                     if (list[preQuot] === c) {  
  352.                         notValue = true;  
  353.                         preQuot = -1;  
  354.                     }  
  355.                 }  
  356.             }  
  357.             //非值  
  358.             else {  
  359.                 //开始引号  
  360.                 if (preQuot == -1) {  
  361.                     preQuot = i;  
  362.                     notValue = false;  
  363.                 }  
  364.                 //结束引号  </


    >> 留言评论