火狐下Ajax的onreadystatechange无法调用函数的解决方法

    技术2022-05-19  32

    1 、问题症状:

    var xmlHttp; function savetodata(){ createXMLHttpRequest(); var rndcode = new Date().getTime(); var Url ="a.asp?cache="+rndcode xmlHttp.onreadystatechange = function(){ ..... } xmlHttp.open ("GET",Url,true ); xmlHttp.send (null); }

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

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

    2 、原因分析:

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

    其二:经测试后发现,onreadystatechangeIE 下都很正常,但在FF3 下,只能运行readyState=0 时的代码。不能运行readyState=4 的代码,在网络上找了一个原因: ajax XMLHttpRequest.onreadystatechange 方法的差异:在 FF 中当状态为 1 (即 XMLHttpRequest 已经调用 open 但还没有调用 send 时), FF 则会继续执行onreadystatechange 后面的代码,到执行完后面的代码后,在执行onreadystatechange 在状态234 的代码,而IE 会等待状态2 的到了,执行完onreadystatechange 中状态234 的代码后,继续执行后面的代码, 这 样问题就出现了,经常我们在onreadystatechange 的代码要处理从服务器上获得的数据(这个数据只有在 onreadystatechange 的状态为4 时,才可以得到),所以这在IE 中不存在问题,因为它会等待onreadystatechange 状态4 到来以后,在执行onreadystatechange 后面的数据,但是由于FF 不会等到onreadystatechange 状态4 到来后在执行 onreadystatechange 后面的代码,所以后面的代码就不能处理从服务器上获得的数据,那该怎么办呢? 解 决方法:使用javascript 的闭包(这个解决方法是从GMAP 中获得灵感的)。我们传递一个函数给onreadystatechange ,在这个函 数中处理从服务器上返回的数据,但是onreadystatechange 是一个无参函数,那该怎么办呢?方法在我前面的Javascript attachEvent 传递参数的办法已 经介绍 了,这里再稍微介绍一下,就是传递一个参数给onreadystatechange ,但是在onreadystatechange 中使用return 一个 无参函数,在这个无参函数中可以使用这个传入的参数。这个方法在IEFF 中都可以正常运行,所以这不失是一个好方法。

    这里提到采用闭包,挺复杂,另外网上有采用了在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='b.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();

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

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

    3 、完美解决方案

    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());

    总算OVER 了,IE6IE 7FF 通用

    4 、我的一点废话补充

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

    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());


    最新回复(0)