EXT在IE中引起很严重的问题并发问题

tiger822 2008-06-16

    我做了一个首页,里面有几个grid显示数据。这些grid是我用了我自己写的一个类,没有什么特别,就是把EditorGridPanel/ColumnModel/ds这些封装起来而已。
     不知道是这几个grid的数据来自同一个url(只是参数不同而已)的原因还是来自同一个类的原因,当用IE打开这个页面,各个store取数的时候明显发生数据混乱,比如本来属于第二个grid的数据跑到第一个grid里面了,而且每次乱跑的现象都不一样,给我的感觉是它们都用了同一个connection,或用了同一个返回事件处理,而且处理搞混乱了!
     我翻了一下Ext的Ajax,竟然是static的,不知道跟这个有没有关系。
     想用Firebug跟踪一下.load方法,可是跟踪不到,各位老大有没有遇到过这种问题??Firefox则完全没问题,比IE强多了,真是汗死我
~~  
tiger822 2008-06-16
  各位有没有遇到过这种问题?
或哪位能跟踪到Ext的ajax发送动作的请支招一二~ 
tiger822 2008-06-16
面对3万多行的代码,firebug立刻举手投降,不可取啊,还是用.net的ide获得一些有用的信息,各位看看:
在ext-base.js中,Ext.lib.Ajax下有个request方法,从这里着手,下面是ajax递交的流程:
request(实例的回调事件放在cb.argument.options.callback里)==》asyncRequest(注意,传到这里本来的cb,在这里传给callback这个变量了,不要被它的名字耍了),asyncRequest会调用o.conn.send向服务器发出请求,在这个动作之前先用handleReadyState设置好一些处理程序。然后收工,垃圾收集等,store.load()方法到此为止。

在asyncRequest方法里面,用getConnectionObject申请了一个连接对象赋给o,接着用这个连接完成发送动作,查看getConnectionObject的代码,是新建连接的,不是使用原来的连接,头晕了,如果是这样就不会出现并发出错啊??!!

在看看handleReadyState,可能问题就出现在这里:
在handleReadyState中做了两个事情:一个是setTimeout,设置操作超时的操作;一个是定时轮询,每50毫秒看看连接o.conn是不是结束了,如果是就删除这个定时器并删除超时计时器等之前设置的垃圾,然后调用handleTransactionResponse(调用之前store设置好的回调事件处理)。
handleReadyState:
   
        handleReadyState:function(o, callback)
        {
            var oConn = this;

            if (callback && callback.timeout) {
                this.timeout[o.tId] = window.setTimeout(function() {
                    oConn.abort(o, callback, true);
                }, callback.timeout);
            }

            this.poll[o.tId] = window.setInterval(
                    function() {
                        if (o.conn && o.conn.readyState == 4) {
                            window.clearInterval(oConn.poll[o.tId]);
                            delete oConn.poll[o.tId];

                            if (callback && callback.timeout) {
                                window.clearTimeout(oConn.timeout[o.tId]);
                                delete oConn.timeout[o.tId];
                            }

                            oConn.handleTransactionResponse(o, callback);
                        }
                    }
                    , this.pollInterval);
        },


  如上面所说的,ajax在EXT中是静态的,并使用时并没有实例化,尽管里面的连接使用的时候有开新连接,可是计时器tID在同一个实例里管理(这个值得怀疑,可是不是重点)
  主要是在asyncRequest里面生成新的连接对象o传到handleReadyState再到setInterval里面的处理程序,通过oConn.handleTransactionResponse传递给store的处理程序,当并发post的时候,刚好在50毫秒的时候有不止一个连接的readyState为4,那么这个o到底是指那一个连接呢?大概这个时候IE头晕了,而伟大的FF依然清醒。
  为什么连接对象的onreadystatechange这个事件不利用而要每50秒查询一次呢??想不明白。
  
jianfeng008cn 2008-06-17
引用
我翻了一下Ext的Ajax,竟然是static的

问题是你的用的 request  要不要用一个看你自己的了 你可以new也可以直接request啊
tiger822 2008-06-17
回楼上,我查阅了EXT的代码, store的.load会调用httpproxy,而httproxy会用Ext.Ajax和服务器通信。而Ext.Ajax是一个static,全局只有一个!Ext.Ajax实质是一个Ext.data.connection的实例。

用.net深入跟踪和加了一些调试信息,发现又出乎意料:
上面重点怀疑的地方居然没问题,o的连接和callback里面的参数都是对应的。
所以再往前追溯,怀疑上.getConnect了,跟踪了一下,FF用的是new XMLHttpRequest();IE用的是new ActiveXObject("MSXML2.XMLHTTP.3.0"),没什么不同。
用一个额外的网络监视工具调试发现,IE实际建立的http连接上,发现IE并发的时候会同时生成两个连接,而FF从头到尾都只是用一个http连接处理(怪不得没事啊,可是效率低),以下是从监视工具截取到的关于错误数据的日志:

连接1发出:start=0&limit=5&ts=1213694647578&action=jrjlc&sort=fe_stockid&dir=ASC
连接1接收:{"found":false,"page":null,"recCount":0,"recordCount":5,"result":[{"ff_name":"涓俊璇佸埜","fe_ddb":-0.16,"_id":0,"fe_jlr":-14129,"fe_zf":-7.77,"fe_stockid":"600030"},{"ff_name":"鍖椾含鍩庝埂","fe_ddb":-4.82,"_id":1,"fe_jlr":-13759,"fe_zf":-9.97,"fe_stockid":"600861"},{"ff_name":"娴烽€氳瘉鍒?,"fe_ddb":-2.92,"_id":2,"fe_jlr":-13356,"fe_zf":-10,"fe_stockid":"600837"},{"ff_name":"涓寲鍥介檯","fe_ddb":-1.58,"_id":3,"fe_jlr":-12586,"fe_zf":-9.96,"fe_stockid":"600500"},{"ff_name":"涓浗鐭冲寲","fe_ddb":-0.16,"_id":4,"fe_jlr":-9919,"fe_zf":-2.26,"fe_stockid":"600028"}],"search_rule":null,"search_rule_label":"鎼滃皨姊濅欢"}
连接2发出:start=0&limit=5&ts=1213694647406&action=jrjlr&sort=fe_stockid&dir=ASC
连接2接收:{"found":false,"page":null,"recCount":0,"recordCount":5,"result":[{"ff_name":"涓俊璇佸埜","fe_ddb":-0.16,"_id":0,"fe_jlr":-14129,"fe_zf":-7.77,"fe_stockid":"600030"},{"ff_name":"鍖椾含鍩庝埂","fe_ddb":-4.82,"_id":1,"fe_jlr":-13759,"fe_zf":-9.97,"fe_stockid":"600861"},{"ff_name":"娴烽€氳瘉鍒?,"fe_ddb":-2.92,"_id":2,"fe_jlr":-13356,"fe_zf":-10,"fe_stockid":"600837"},{"ff_name":"涓寲鍥介檯","fe_ddb":-1.58,"_id":3,"fe_jlr":-12586,"fe_zf":-9.96,"fe_stockid":"600500"},{"ff_name":"涓浗鐭冲寲","fe_ddb":-0.16,"_id":4,"fe_jlr":-9919,"fe_zf":-2.26,"fe_stockid":"600028"}],"search_rule":null,"search_rule_label":"鎼滃皨姊濅欢"}

连接1发出:start=0&limit=5&ts=1213694647796&action=jrbkzj&dir=desc&sort=fh_name
连接1接收:{"found":false,"page":null,"recCount":0,"recordCount":5,"result":[{"fh_stocks":16,"fi_bkid":410,"fh_name":"鏁欒偛浼犲獟,410","_id":0,"fi_pjzf":-4.4,"fi_jlr":-5517},{"fh_stocks":23,"fi_bkid":411,"fh_name":"鏃呮父閰掑簵,411","_id":1,"fi_pjzf":-4.01,"fi_jlr":-6026},{"fh_stocks":21,"fi_bkid":406,"fh_name":"渚涙按渚涙皵,406","_id":2,"fi_pjzf":-4.38,"fi_jlr":-11184},{"fh_stocks":37,"fi_bkid":401,"fh_name":"鐢靛櫒,401","_id":3,"fi_pjzf":-3.83,"fi_jlr":-13623},{"fh_stocks":31,"fi_bkid":398,"fh_name":"閫犵焊鍗板埛,398","_id":4,"fi_pjzf":-4.4,"fi_jlr":-14202}],"search_rule":null,"search_rule_label":"鎼滃皨姊濅欢"}
连接2发出:start=0&limit=5&ts=1213694647921&action=jrbkzj&dir=ASC&sort=fh_name
连接2接收:{"found":false,"page":null,"recCount":5,"recordCount":5,"result":[{"fe_dh_bfbi":0.69,"fe_dh_cc":65.5,"ff_name":"ST鏈涙槬鑺?,"fe_dh_simu":0,"fe_date":"2008-06-11","_id":0,"fe_bwb":-18,"fe_jlr":-1632,"fe_dh_jmr":792,"fe_zf":-4.99,"fe_stockid":"600645"},{"fe_dh_bfbi":0.66,"fe_dh_cc":30,"ff_name":"闆烽福绉戝寲","fe_dh_simu":52,"fe_date":"2008-06-11","_id":1,"fe_bwb":0,"fe_jlr":-128,"fe_dh_jmr":385,"fe_zf":1.47,"fe_stockid":"600985"},{"fe_dh_bfbi":0.64,"fe_dh_cc":57.1,"ff_name":"棣栧紑鑲′唤","fe_dh_simu":1367,"fe_date":"2008-06-11","_id":2,"fe_bwb":2,"fe_jlr":-64,"fe_dh_jmr":1239,"fe_zf":-5.72,"fe_stockid":"600376"},{"fe_dh_bfbi":0.6,"fe_dh_cc":48.7,"ff_name":"婀橀偖绉戞妧","fe_dh_simu":0,"fe_date":"2008-06-11","_id":3,"fe_bwb":0,"fe_jlr":188,"fe_dh_jmr":475,"fe_zf":1.05,"fe_stockid":"600476"},{"fe_dh_bfbi":0.58,"fe_dh_cc":50.6,"ff_name":"鑰佺櫧骞查厭","fe_dh_simu":-39,"fe_date":"2008-06-11","_id":4,"fe_bwb":0,"fe_jlr":80,"fe_dh_jmr":557,"fe_zf":0.28,"fe_stockid":"600559"}],"search_rule":null,"search_rule_label":"鎼滃皨姊濅欢"}
tiger822 2008-06-17
上面的日志是实际上IE跟服务器的通信数据包,可以看到:
第1条日志的action跟第3条日志的action明显不同,可是接收内容一样;
第6条日志的dir跟第8条日志的dir不一样,其他一致,可是返回来内容完成不同;

带出两个问题:
IE的XMLHTTP并发有问题?
我的web服务有问题?

有空再研究~ 
kuru 2008-06-17
检查一下你的两个grid的id是不是相同的,注意一定不能相同 的
tiger822 2008-06-18
回楼上的兄弟:grid的id为识别dom或el而设,跟通讯没什么关系,而且我我的id是唯一的。
经过调试,事件明朗化:
    在怀疑microsoft和我自己程序上,当然首先排查自己了,毕竟人家是千锤百炼出来的:)
    在服务器程序上加了一些调试输出,发现取回来的查询参数重复了!因为回送的数据是根据查询参数得到的,而查询参数取错了,当然返回错误!
     参数取混乱,直觉告诉我应该是全局变量的问题,这个问题上我已经很小心了,因为踩过几次这样的坑。翻阅了一下代码,果然有个core类被定义为public,我晕了,虽然每次接收post的时候new一次,可是被public了各个connection都用最新的core操作,而获取参数是通过core完成的,  狂改了一顿后,一切正常。
    
     总结一下这几天的发现:
     EXT所有的通过httpproxy取数都是通过Ext.Ajax这个实例操作的,它实质是Ext.data.connection的一个实例,static了,全局只有一个实例。
     Ext.Ajax request的时候根据浏览器版本的不同建立一个新的ConnectionObject,如果是IE,则根据IE的版本最优化建立连接(赞一个),然后设置timeout处理事件、发送请求,然后每50毫秒检查一下连接是否正常返回,如果为真,则调用store的回调事件。
     根据网络监控工具发现,如果是并发请求(同时发送不止一个请求),IE会视情况而定,同时建立两个或以上的TCP/IP连接向服务器发送请求,在我的页面上会并发7个请求,但IE只建立两个TCP/IP连接发送;而Firefox则只是用主连接逐个依次发送,并没有真正做到并发。从这个测试上可以看到,IE效率比FF要高。
     Firebug在调试css/dom/小巧的script方面真的没话说,可是遇到EXT这种庞然大物就不行了,而.NET的IDE就驾轻就熟,不得不佩服微软的实力。
     题外话:升级到FF3,发现EXT的DateField日期控件跟FF3不兼容,点击日期的小图标,整个页面都撑开了,真是倒塌。
     弄不明白为什么EXT用定时检查的方法处理连接是否正常结束的问题,每50毫秒一次,个人认为效率影响方面还是挺吓人的,所以自己修改成事件驱动了,一切正常。
     最后谢谢上面两位兄弟的关注。
cheng022074 2008-06-29
楼上的,谢谢你提醒每50毫秒检查Bug
Global site tag (gtag.js) - Google Analytics