firefox下对ajax的onreadystatechange的支持情况分析及解决

一、问题: 

var xmlHttp; 
function savecarttodata(){ 
createXMLHttpRequest(); 
var rndcode = new Date().getTime(); 
var CartUrl ="a.asp?cache="+rndcode 
xmlHttp.onreadystatechange = function(){ 
..... 

} 
xmlHttp.open ("GET",CartUrl,true); 
xmlHttp.send(null); 
} 

上面的这段代码, xmlHttp.onreadystatechange = function(){.....};可以在FF下执行,但是如果改成 

xmlHttp.open ("GET",Url,false);时就不行了,今天被这个问题整的晕头转向。 

原因分析: 

其一:这时不能用xmlHttp.send(),需要内容,如果没有内容,要用NULL 

其二:经测试后发现,onreadystatechange在IE下都很正常,但在FF3下,只能运行readyState=0时的代码。不能运行readyState=4的代码,在网络上找了一个原因: 
在ajax的XMLHttpRequest.onreadystatechange方法的差异:在FF中当状态为1(即XMLHttpRequest已经调用open但还没有调用send时),FF则会继续执行onreadystatechange后面的代码,到执行完后面的代码后,在执行onreadystatechange在状态2,3,4的代码,而IE会等待状态2的到了,执行完onreadystatechange中状态2,3,4的代码后,继续执行后面的代码,这样问题就出现了,经常我们在onreadystatechange的代码要处理从服务器上获得的数据(这个数据只有在onreadystatechange的状态为4时,才可以得到),所以这在IE中不存在问题,因为它会等待onreadystatechange状态4到来以后,在执行onreadystatechange后面的数据,但是由于FF不会等到onreadystatechange状态4到来后在执行onreadystatechange后面的代码,所以后面的代码就不能处理从服务器上获得的数据,那该怎么办呢? 

解决方法:使用javascript的闭包(这个解决方法是从GMAP中获得灵感的)。我们传递一个函数给onreadystatechange,在这个函数中处理从服务器上返回的数据,但是onreadystatechange是一个无参函数,那该怎么办呢?方法在我前面的Javascript attachEvent传递参数的办法已经介绍 了,这里再稍微介绍一下,就是传递一个参数给onreadystatechange,但是在onreadystatechange中使用return一个无参函数,在这个无参函数中可以使用这个传入的参数。这个方法在IE和FF中都可以正常运行,所以这不失是一个好方法。 

这里提到采用闭包,挺复杂,另外网上有采用了在FF下用onload,也是不管用。经过对错误排除,上面摘要提到的原因,才是根本的,也就是说,在FF下,第一次执行完onreadystatechange后,继续执行到send,但后面就不会再回头执行onreadystatechange,一直傻傻的走下去。 

 

我直接改成:

xmlHttp.onreadystatechange = xmlHandle; 
xmlHttp.open ("GET",Url,false); 
xmlHttp.send(null); 
xmlHttp.onreadystatechange = xmlHandle; //这里加一行挡住FF,让它再搞一次。 


function xmlHandle(){ 
if (xmlHttp.readyState < 4){ 
...... 
}else if (xmlHttp.readyState == 4 && xmlHttp.status == 200){ 
var cartResult = Number(xmlHttp.responseText); 
if (cartResult == 1){ 
window.location.href='a.asp'; 
}else if (cartResult == 2){ 
......; 
}else{ 
window.location.href='/'; 
} 
} 
} 

但是这样也不行,原来ff 3改成:xmlHttp.onreadystatechange = xmlHandle();然而加了括号,IE又不行,唉,原来就觉得FF是鸡皮,现在感觉FF纯属一个打着“支持标准”的称号,却是干着浪费程序员时间的垃圾。但手上这个程序又实在重要,没办法,只有再调试看看有没有更简单的办法,如下: 

xmlHttp.open ("GET",Url,false); 
xmlHttp.send(null); 
if(xmlHttp.status==200) 
xmlHandle(); 

这段代码在IE和FF下可以通用。但由于是同步调用,需要在readyState<4时未取得结果前出现提示,这对于网速慢的客户很友好。然而要在本机获得这种等待反应时的情况,由于本机反应快,会造成看不到给客户提示,因此暂时先不用这个代码 

只有加入浏览器类型分析。 

function getOs() 
{ 
var OsObject = ""; 
if(navigator.userAgent.indexOf("MSIE")>0) { 
return "MSIE"; //IE浏览器 
} 
if(isFirefox=navigator.userAgent.indexOf("Firefox")>0){ 
return "Firefox"; //Firefox浏览器 
} 
if(isSafari=navigator.userAgent.indexOf("Safari")>0) { 
return "Safari"; //Safan浏览器 
} 
if(isCamino=navigator.userAgent.indexOf("Camino")>0){ 
return "Camino"; //Camino浏览器 
} 
if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0){ 
return "Gecko"; //Gecko浏览器 
} 
} 

然后把AJAX代码改为: 

var rndcode = new Date().getTime(); 
var CartUrl ="a.asp?cache="+rndcode 
var btype=getOs(); 
xmlHttp.onreadystatechange = (btype!="Firefox")?xmlHandle():xmlHandle; 
xmlHttp.open ("GET",CartUrl,false); 
xmlHttp.send(null); 
xmlHttp.onreadystatechange = (btype!="Firefox")?xmlHandle():xmlHandle; 

例二 

//获取游览器的类型,为解决onreadystatechange不兼容的问题 
function getOs() 
{ 
var OsObject = ""; 
if(navigator.userAgent.indexOf("MSIE")>0) { 
return "MSIE"; //IE浏览器 
} 
if(isFirefox=navigator.userAgent.indexOf("Firefox")>0){ 
return "Firefox"; //Firefox浏览器 
} 
if(isSafari=navigator.userAgent.indexOf("Safari")>0) { 
return "Safari"; //Safan浏览器 
} 
if(isCamino=navigator.userAgent.indexOf("Camino")>0){ 
return "Camino"; //Camino浏览器 
} 
if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0){ 
return "Gecko"; //Gecko浏览器 
} 
} 
var objHttp; 
function searchCommodityByGroupId(groupId) 
{ 
objHttp = getHttpRequest(); 
var tt=new Date(); 
var url="getCommodityListByGroupId.htm?commodityGroupId="+groupId+"&time="+tt; 
var btype=getOs(); 

objHttp.onreadystatechange=(btype=="Firefox")?getCommodity():getCommodity; 
objHttp.open("GET",url,false); 
objHttp.send(null); 
objHttp.onreadystatechange=(btype=="Firefox")?getCommodity():getCommodity; 
} 
function getCommodity(){ 

if(objHttp.readyState==4) 
{ 
if(objHttp.status==200) 
{ 
document.getElementById("commodityDiv").innerHTML=objHttp.responseText; 
} 
} 
} 

function getHttpRequest(){ 
var httpRequest; 
if (window.XMLHttpRequest){ 
httpRequest = new XMLHttpRequest(); 
if (httpRequest.overrideMimeType){ 
httpRequest.overrideMimeType('text/xml'); 
} 
}else if (window.ActiveXObject){ 
try{ 
httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); 
}catch(e){ 
try { 
httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 
}catch(e){} 
} 
} 
return httpRequest; 
} 

我觉得那个判断各个浏览器的有些多余,直接只判断火狐吧,如下

var browserflag=0;
if(isFirefox=navigator.userAgent.indexOf("Firefox")>0){
browserflag=1
}
xmlHttp.onreadystatechange = (browserflag!=1)?(serverResponse):(serverResponse());
xmlHttp.open ("GET","taogogo.py",false);
xmlHttp.send(null);
xmlHttp.onreadystatechange = (browserflag!=1)?(serverResponse):(serverResponse());

 

上面为查找资料得到

但是还是不行!!!

 

var xmlhttp = loadXMLDoc();  
var startRequestMethod = function(obj){  
    var url = "http://www.xxxx.com?id=1";         
    xmlhttp.open("get", url, false);    //这是个同步请求     
    xmlhttp.send(null);        
    xmlhttp.onReadyStateChange = stateChange;  //注意这儿  
}  
  
var stateChange = function(){  
    if(xmlhttp.readyState == 4){  
       if (xmlhttp.status == 200){  
            //需要执行的代码  
       }else{  
            alert("操作失败!");  
       }  
    }  
}  
  
var loadXMLDoc = function(){  
  var xmlhttp = null;  
  if(window.XMLHttpRequest){  
      xmlhttp = new XMLHttpRequest();  
  }else if (window.ActiveXObject){  
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  
  }  
  return xmlhttp;  
}  

查了资料后发现,FireFox3下同步请求不需要等待onReadyStateChange,而直接执行后续代码,于是只要将原先代码中

xmlhttp.onReadyStateChange = stateChange;    这句注掉,然后直接调用stateChange()方法。代码如下:

var startRequestMethod = function(obj){  
    var url = "http://www.xxxx.com?id=1";         
    xmlhttp.open("get", url, false);    //这是个同步请求     
    xmlhttp.send(null);        
    //xmlhttp.onReadyStateChange = stateChange;  //注意这儿  
    stateChange();  
}  

综合上面的,可以对同步和异步请求做个判断,做个通用化的处理,代码如下:

var startRequestMethod = function(obj){  
    var url = "http://www.xxxx.com?id=1";     
    var ansyType = true; //默认异步   
    xmlhttp.open("get", url, ansyType); //这是个同步请求     
    xmlhttp.send(null);  
    if(ansyType){  //异步  
       xmlhttp.onReadyStateChange = stateChange;  
    }else{         //同步  
       stateChange();  
    }        
}  

 

最后,上传自己写的

乱了点,但是至少是个总结

$("#changeCoupon").click(function () {
                var couponVal = $("#selQuans").val();
                var ary = couponVal.split("$");
                var couponType = ary[0];
                var parValue = ary[1];
                if (couponType == "") {
                    alert("请选择优惠券类别");
                    $("#selQuans").focus();
                    return;
                }
                var consumedIntegral = $('#jifen').val();
                var canUseIntergral = $('#lab_jifen').text();
                if (parseInt(canUseIntergral) < parseInt(consumedIntegral)) {
                    alert("抱歉您的积分还不够兑换该券");
                    $("#selQuans").focus();
                    return;
                }
                var postdata = { coupontype: couponType, parvalue: parValue, consumedintegral: consumedIntegral };
                //最起初方法
                //$.post("services/Integral2Coupon.ashx", postdata, function (json) {
                //     if (json.error_code == 0) {
                //     var integralLogList = $("#tab0\\.page0");
                //     var tpl = $("#integrallogtpl").html();
                //     var html = _.template(tpl, json.data.integralLog);
                //     integralLogList.append(html);

                //     var couponlist = $("#tb0\\.pg0");
                //     tpl = $("#coupontpl0").html();
                //     html = _.template(tpl, json.data.coupon);
                //     couponlist.append(html);

                //     var integraltocouponList = $("#tab0\\.page1");
                //     tpl = $("#integraltocoupontpl").html();
                //     html = _.template(tpl, json.data.integralToCoupon);
                //     integraltocouponList.append(html);

                //        alert("积分换券成功!")
                //     }
                //     else
                //        alert(json.data.msg)
                //     });

                //09-01 改变 ajax 方式 采用判断浏览器改同步或异步方式 strat
var browserflag = 0; var ansyType = true; //默认异步 if (isFirefox = navigator.userAgent.indexOf("Firefox") > 0) { browserflag = 1; ansyType = false; } var args = "coupontype=" + couponType + "&parvalue=" + parValue + "&consumedintegral=" + consumedIntegral; var xmlhttp; if (window.XMLHttpRequest) { //如果为 Mozilla,Safari 等浏览器 xmlhttp = new XMLHttpRequest(); if (xmlhttp.overrideMimeType) xmlhttp.overrideMimeType('text/xml'); } else if (window.ActiveXObject) { //如果是Ie浏览器 try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } } } var url = "services/Integral2Coupon.ashx"; //xmlhttp.onreadystatechange = (browserflag != 1) ? serverResponse() : serverResponse; xmlhttp.open("POST", url, ansyType); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); xmlhttp.send(args); if (ansyType) { //异步 xmlhttp.onReadyStateChange = stateChange; } else { //同步 stateChange(); } //xmlhttp.onreadystatechange = (browserflag != 1) ? serverResponse() : serverResponse; function serverResponse() { if (xmlhttp.readyState == 4) //readyState == 4 表示服务器返回完成数据了。之前可能会经历2(请求已发送,正在处理中)、3(响应中已有部分数据可用了,但是服务器还没有完成响应的生成) { if (xmlhttp.status == 200) //如果状态码为200则是成功 { //onsuccess(xmlhttp.responseText); //var json = JSON.parse(xmlhttp.responseText); var jsons = xmlhttp.responseText; var json; if (typeof (JSON) == 'undefined') { json = eval("(" + jsons + ")"); } else { json = JSON.parse(jsons); } if (json.error_code == 0) { var integralLogList = $("#tab0\\.page0"); var tpl = $("#integrallogtpl").html(); var html = _.template(tpl, json.data.integralLog); integralLogList.append(html); var couponlist = $("#tb0\\.pg0"); tpl = $("#coupontpl0").html(); html = _.template(tpl, json.data.coupon); couponlist.append(html); var integraltocouponList = $("#tab0\\.page1"); tpl = $("#integraltocoupontpl").html(); html = _.template(tpl, json.data.integralToCoupon); integraltocouponList.append(html); alert("积分换券成功!") } else alert(json.data.msg) } else { alert("AJAX服务器返回错误!"); } } }; //ajax end });

 

posted @ 2014-09-01 11:27  luoch-  阅读(327)  评论(0编辑  收藏  举报