关于ajax的debug小记一则--小问题往往容易被忽略

本文记录了作者在使用AJAX加载并设置表格样式时遇到的问题及解决过程。问题表现为Firefox浏览器下表格数据加载正常但样式设置失败,而在IE浏览器下却能正常工作。最终发现原因是AJAX异步请求导致DOM元素更新滞后。

今天写程序的时候遇到一个问题,费了不少功夫才把bug给找出来了。本来其实是很简单的问题,不过一开始的时候还是忽略了。看来低级错误还是一如既往的难以避免,特以此文记之,希望以后不会再犯同类的错误。

问题描述:

主页上定义用来显示数据的div,当页面触发了某个事件(如<select>的onchange()),就从database加载数据在该div内显示出来。而数据是用一个table来显示的,该table有css文件和javascript来设置style。

因为涉及到database的数据加载,我决定用ajax来做。于是,整个流程如下:

触发事件(select.onchange()) --> ajax (XMLHttpRequest) --> set table style(用css和javascript方法来实现)

为了方便代码的重用,把ajax那部分做成了单独的一个loadXMLDoc.js文件,并设定了一些传入参数,使得该部分代码更通用化,代码如下:

 

/*
This function is to load a file by sending xmlhttprequest
When the data is being transferred, show some information to the user (usually, the info would be a loading image)
When the file loaded, display the file in the specified div
@docUrl: the file to be laoded
@docDisDiv: the div to display the file
@infoHtml: the html string, eg: "<img src='image/22-1.gif' alt='loading...'></img>";
@infoDiv: the div to display the waiting info
*/
 
function loadXMLDoc(docUrl,docDisDiv,infoHtml,infoDiv){
    
var xmlhttp=null;
    
if (window.XMLHttpRequest){// code for Firefox, Opera, IE7, etc.
        xmlhttp=new XMLHttpRequest();
    }
else if (window.ActiveXObject){// code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
if (xmlhttp!=null){
        xmlhttp.onreadystatechange 
= function(){
            
if (xmlhttp.readyState==4){// 4 = "loaded"
                if (xmlhttp.status==200){// 200 = "OK"
                    document.getElementById(docDisDiv).innerHTML=xmlhttp.responseText;//load data
                    document.getElementById(infoDiv).innerHTML = "";//data loaded, clear waiting info
                }else{
                    alert(
"Problem retrieving data:" + xmlhttp.statusText);
                }
            }
else{
                document.getElementById(infoDiv).innerHTML 
= infoHtml;//waiting data transfering, display waiting info...
            }
        }
        xmlhttp.open(
"GET",docUrl,true);
        xmlhttp.send(
null);
    }
else{
        alert(
"Your browser does not support XMLHTTP.");
    }
}

熟悉ajax的同志都应该清楚,这是对一个典型的“ajax文件加载请求”代码,只是里面做了作了小小的修改,传入了几个参数而已。

 

好了,下面再来看看op.php内的内容:

<div>
<table id="listTable">
<caption>The Latest Purchase Order</caption>
    
<thead>
    
<tr class="odd">
        
<th scope="col" abbr="ORDER ID">Order ID</th>
        
<th scope="col" abbr="SELLER ID">Seller ID</th>
        
<th scope="col" abbr="EMPLOYEE ID">Employee ID</th>
        
<th scope="col" abbr="DATE">Date</th>
        
<th scope="col" abbr="STATUS">Status</th>
    
</tr>    
    
</thead>   
    
<tbody>
<?php
require_once'lib/ListTableData.php';
$table = "order_purchase";
$fields = array("order_id","seller_id","employee_id","date","status");
$sql = "SELECT * FROM order_purchase ORDER BY date DESC LIMIT 20";
$dataList = new ListTableData($table,$fields,$sql);
$dataList->printData();
?>
</tbody>
</table>
</div>

关于这个文件的代码,其实也不用理会,只要明白,这个table有个id属性,然后外部代码根据这个id就可以将这个table的style按照css和js定义好风格来设置。

 

最后,我们再来看看在index.php中代码是怎么被调用的:

var docUrl = "op.php";    
var docDiv = "right_top_itemlist";
var infoHtml = "<img src='image/22-1.gif' alt='loading...'></img>";
var infoDiv = "loading_info_div";

loadXMLDoc(docUrl,docDiv,infoHtml,infoDiv);//load file and construct table
setTableStyle(“listTable”);//set the style of the table

loadXMLDoc(docUrl,docDiv,infoHtml,infoDiv);    这一行就没什么说的了,就是调用那个js文件的方法。

setTableStyle();    这一行目的就是将加载后的table的style设置好,至于当中的style代码跟这个主题无关紧要,因此不用理会,知道它的作用就行了。

简单概括一下就是:发送ajax请求,文件加载的时候显示等候信息,当文件加载完就以table的形式显示数据,然后将table的style设置好。

好了,开始测试。测试结果:在IE下,成功得到了设想当中的效果,可是在Firefox下,只能成功加载数据,但表格的style设置不成功。

于是用firefox的debug工具,在其中一个js语句内:

var Ptr=document.getElementById(id).getElementsByTagName('tr');

出现了如下的错误信息:error document.getElementById(id) has no properties(其中的id就是我从外面传进去的一个table的名字,在这里也就是“listTable”了) 。

我一直都很纳闷,不知道为什么会出现这个error,因为我通过alert()方法测试,确定“listTable”已经正确传进去了,但是为什么却又出现了这个错误呢?代码改来改去,不断的测试,可还是百思不得其解。。。

后来,我在设置table的那段代码中加入了一个语句来测试所有"tr”标签的总数量,结果发现,每次alert出来的<tr>标签的数量竟然不是当前加载的table的<tr>的数量,而是上一次加载的table的那个数量,也就是说,这段"setTableStyle" 代码set的根本就不是当前显示数据的那个table,而是上一次加载数据的那个table。(在这里要补充一下:由于加载的那些数据是动态的,因此每次加载的行数,也就是<tr>的数量都不同的)那它的style是当然不可能被正确设置了。可是,为什么会出现这样的问题呢?明明就是在loadXMLDoc()之后setTableStyle()了啊。。。并且,在IE下面也是成功通过的啊。。。到底是哪里出的问题呢?想啊想,debug啊debug。。。几乎抓破头皮了,还是没找出来原因。。。

后来,突然脑海好像闪了一下的样子。。。我想到了些东西。。。

对!问题就在这里,一定是这里:
        xmlhttp.onreadystatechange = function(){
            
if (xmlhttp.readyState==4){// 4 = "loaded"
                if (xmlhttp.status==200){// 200 = "OK"
                     ...

当xmlhttp请求发送出去以后,先从database提取数据,然后数据返回来,然后才去构造那个"listTable”,而并不是马上就将"listTable”构建的,是需要一定时间的,这也是为什么我们很多时候将loading image显示出来的原因!显然,当loadXMLDoc()被执行之后,紧跟着就执行setTableStyle(),从表面上看执行顺序是没错的,然而实际上是,当setTableStyle()开始运行时,xmlhttp还在请求当中,数据还没完全返回来,"listTable” 根本还没有构建起来。。。这也就是为什么,后来我alert()得到的<tr>数目并不是当前显示的table的tr数目,而是上一个table的tr数目--因为这时候,新的table根本还没构建。。。也就是说,当新的table构建好以后,根本就没有对当前的table进行setTableStyle(),而是对上个table做了。

后来将setTableStyle()的调用放在了xmlhttp的请求完成后,也就是:

xmlhttp.onreadystatechange = function(){
     
if (xmlhttp.readyState==4){// 4 = "loaded"
            if (xmlhttp.status==200){// 200 = "OK"
                   document.getElementById(docDisDiv).innerHTML=xmlhttp.responseText;//load data
                   document.getElementById(infoDiv).innerHTML = "";//data loaded, clear waiting info
                   setTableStyle();
                }
else{
                    alert(
"Problem retrieving data:" + xmlhttp.statusText);
                }

终于,成功了。再debug就没有错了,无论是在ie下还是ff下。。。

其实说了一大堆也就是一言可以蔽之:在使用ajax xmlhttprequest的时候要注意,方法的调用时机要合适,不能想当然。

正如我在文章开头说到的,本来是一个很基本的问题,但是因为没有注意好,结果弄了大半天才高明白,bs一下自己。。。

不过,这里又提出了一个问题,不知道为什么,在ie下面,没有出现这个问题的呢???这个问题所反映出的ie和ff两个浏览器的机制的不同点究竟是什么?值得探讨。。。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值