emu in blogjava

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            171 隨筆 :: 103 文章 :: 1052 評(píng)論 :: 2 Trackbacks
          這個(gè)問(wèn)題長(zhǎng)期以來(lái)一直一個(gè)隨機(jī)出現(xiàn),又十分難以重現(xiàn)和定位。幾經(jīng)努力之后定位到了,在一個(gè)帶有復(fù)雜的內(nèi)嵌iframe的頁(yè)面,當(dāng)內(nèi)嵌的iframe正在渲染的過(guò)程中關(guān)閉IE 瀏覽器的時(shí)候,會(huì)比較容易發(fā)生這個(gè)問(wèn)題。

          比較容易猜想的是IE在關(guān)閉iframe的時(shí)候出現(xiàn)了某些問(wèn)題。猜測(cè)是幾個(gè)iframe相互有通過(guò)top的腳本調(diào)用有關(guān)系,或者幾個(gè)iframe和top都在各自不同的域名下有關(guān)系,但是頁(yè)面太復(fù)雜進(jìn)一步定位具體是什么問(wèn)題十分困難(當(dāng)試圖簡(jiǎn)化頁(yè)面的時(shí)候,問(wèn)題往往就不能重現(xiàn)了)。而且問(wèn)題出現(xiàn)在瀏覽器內(nèi)部,就算具體定位到了不一定就能夠解決。所以更容易和更有意義的,可能是回避“連續(xù)彈出新窗口”這個(gè)問(wèn)題。

          最開始的想法是,IE既然在出問(wèn)題的時(shí)候是正在渲染iframe,那么此時(shí)可能cpu特別繁忙導(dǎo)致了問(wèn)題,如果可以回避cpu的最高峰期,把渲染iframe的動(dòng)作做一定的延遲,也許就可以解決問(wèn)題。試驗(yàn)后發(fā)現(xiàn),只是減緩了頁(yè)面的展現(xiàn)速度,對(duì)問(wèn)題的解決基本沒(méi)用幫助。

          換個(gè)想法,想想如果我們自己做瀏覽器,我們?cè)谔幚磉@個(gè)問(wèn)題的時(shí)候會(huì)怎么做呢,容易出什么問(wèn)題呢?我們可以做這樣的猜測(cè):IE關(guān)閉窗口的時(shí)候,是先關(guān)閉和回收了最外層的window對(duì)象,然后收集它引用的各種資源,一一進(jìn)行關(guān)閉和回收。也就是說(shuō),相當(dāng)于一個(gè)隊(duì)列式(先打開的window對(duì)象先銷毀回收,后打開(被引用)的window對(duì)象后銷毀和回收)或者遞歸式(父window對(duì)象先銷毀,子window對(duì)象后銷毀)的操作:。

          看看下面這個(gè)測(cè)試頁(yè)面的關(guān)閉順序,其實(shí)很耐人尋味(把代碼保存為一個(gè)html文件后刷新頁(yè)面):

          <iframe name="emu1" src="javascript:'<iframe name=emu2></iframe><iframe name=emu3></iframe>'"></iframe>
          <iframe name="emu4" src="javascript:'<iframe name=emu5></iframe><iframe name=emu6></iframe>'"></iframe>
          <SCRIPT LANGUAGE="JavaScript">
          setTimeout(
          function(){
              window.attachEvent('onbeforeunload',
          function(){alert('parent')})
              frames['emu1'].attachEvent('onbeforeunload',
          function(){alert('iframe1')})
              frames['emu1'].frames['emu2'].attachEvent('onbeforeunload',
          function(){alert('iframe2')})
              frames['emu1'].frames['emu3'].attachEvent('onbeforeunload',
          function(){alert('iframe3')})
              frames['emu4'].attachEvent('onbeforeunload',
          function(){alert('iframe4')})
              frames['emu4'].frames['emu5'].attachEvent('onbeforeunload',
          function(){alert('iframe5')})
              frames['emu4'].frames['emu6'].attachEvent('onbeforeunload',
          function(){alert('iframe6')})
          },
          0)
          </SCRIPT>


          這樣子很容易帶來(lái)的一個(gè)問(wèn)題是,對(duì)象的銷毀和資源的回收工作,一般來(lái)說(shuō)是作為低優(yōu)先級(jí)的操作,要為高優(yōu)先級(jí)的操作讓路的,那么在top窗口被銷毀回收的時(shí)候,各個(gè)iframe的渲染工作,作為優(yōu)先級(jí)比較高的計(jì)算,仍在繼續(xù)進(jìn)行。等到各個(gè)iframe渲染完成了以后,才發(fā)現(xiàn)他本來(lái)以為一直在哪里的parent(或者top)句柄,現(xiàn)在指向了一個(gè)隨機(jī)的位置,于是就發(fā)生了不可預(yù)測(cè)的后果。

          假如問(wèn)題真的是這樣,那么解決方案可能是
          1 對(duì)關(guān)閉操作觸發(fā)的銷毀和回收操作,提高優(yōu)先級(jí)別,或者
          2 一但觸發(fā)關(guān)閉操作,立刻主動(dòng)停止所有的渲染操作,全部資源等待回收,或者
          3 對(duì)window的關(guān)閉操作采用棧式的順序,晚創(chuàng)建的先銷毀,或者或者冒泡式的時(shí)序,子窗口先銷毀再銷毀父窗口。
          現(xiàn)在我們的問(wèn)題是瀏覽器自己是不會(huì)去調(diào)整自己的運(yùn)算優(yōu)先級(jí)和銷毀順序的,那么我們能否用腳本來(lái)幫助它調(diào)整一下window對(duì)象的銷毀次序呢:

          <div id="emu"><iframe src="javascript:'this is an iframe'"></iframe></div>
          <SCRIPT LANGUAGE="JavaScript">
          window.attachEvent('onbeforeunload',
          function(){document.getElementById("emu").innerHTML="iframe closed";alert('parent')})
          </SCRIPT>


          經(jīng)過(guò)這樣的處理后,在可以穩(wěn)定重現(xiàn)連續(xù)打開IE窗口的計(jì)算機(jī)上,此問(wèn)題消失,應(yīng)該說(shuō)得到了初步解決。

          這個(gè)問(wèn)題其實(shí)歷史非常悠久了,flashget論壇有人認(rèn)為是flashget的問(wèn)題:
          http://bbs.flashget.com/post.php?action=reply&fid=14&tid=2461&repquote=16576&extra=

          阿里巴巴也蒙受了不白之冤:
          http://club.china.alibaba.com/forum/thread/view/_22629427_.html

          同樣不幸的還有土豆網(wǎng),土豆的官方聲明把箭頭指向了BHO,不知是否有根據(jù),實(shí)際試驗(yàn)至少有部分機(jī)器確實(shí)選中了“啟用第三方瀏覽器擴(kuò)展”,并且禁止此選項(xiàng)后問(wèn)題解決了,但是這個(gè)操作也很難作為一個(gè)解決方案。
          http://bbs.tudou.com/topic/20061231/5686

          但是網(wǎng)上搜不到其他相關(guān)的解決方案,不少人都以為是中了木馬、病毒或者打開的網(wǎng)頁(yè)帶有惡意腳本,msdn上一時(shí)也搜不到相關(guān)的資料。特此貼出來(lái)共享 。

          posted on 2007-07-06 20:41 emu 閱讀(4519) 評(píng)論(2)  編輯  收藏

          評(píng)論

          # re: 解決IE關(guān)閉頁(yè)面時(shí)連續(xù)彈出新窗口的bug 2007-07-09 13:41 風(fēng)之石
          那以后在包含IFRAME的頁(yè)中都需要這樣處理一下咯? :)  回復(fù)  更多評(píng)論
            

          # re: 解決IE關(guān)閉頁(yè)面時(shí)連續(xù)彈出新窗口的bug 2007-11-14 16:39 emu
          stackhuang同學(xué)給出的權(quán)威解釋是:

          當(dāng)Navigate一個(gè)網(wǎng)頁(yè)的時(shí)候,Navigate在設(shè)置了URL以后就返回了,但Navigate設(shè)置了一個(gè)Timer,當(dāng)Timer到達(dá)的時(shí)候就去顯示一個(gè)頁(yè)面。或者是,當(dāng)頁(yè)面在下載的時(shí)候,當(dāng)下載完成,也會(huì)產(chǎn)生一個(gè)新的瀏覽,還有腳本也可以導(dǎo)致一個(gè)新的瀏覽。
          瀏覽一個(gè)網(wǎng)頁(yè)是需要一個(gè)容器的,也就是Browser。默認(rèn)情況下,IE會(huì)去找這個(gè)Browser,如果找到,則在這個(gè)Browser中打開。如果找不到,就會(huì)新創(chuàng)建一個(gè)IE,在新的IE中打開,那么,問(wèn)題就在這里,如果這個(gè)瀏覽操作是由一個(gè)Timer引起,新打開IE的方式是不會(huì)去停止這個(gè)Timer的,于是Timer繼續(xù)運(yùn)行,導(dǎo)致不斷的打開IE窗口。
          那么這個(gè)容器(Browser)怎么會(huì)不在呢?是因?yàn)閷?duì)IE的使用不當(dāng)造成的,如果IE沒(méi)有完全釋放,但同時(shí)又關(guān)閉了IE的窗口,那么就會(huì)造成IE不停的彈出。
          那么這個(gè)問(wèn)題為什么是隨機(jī)的呢?因?yàn)槭芫W(wǎng)絡(luò)環(huán)境,機(jī)器CPU繁忙程度的影響,新打開一個(gè)頁(yè)面的時(shí)機(jī)是不確定的

          ------------------------------------------------
          stackhuang同學(xué)的補(bǔ)充解釋:

          大概就是,IE在瀏覽的時(shí)候會(huì)判斷一個(gè)標(biāo)志,如果true,則在當(dāng)前窗口中打開,為false則在新窗口中打開,當(dāng)IE窗口已經(jīng)關(guān)閉的時(shí)候,如果IE釋放不完全,那么可能Document對(duì)象還存在,但這個(gè)標(biāo)志就為false了,于是新打開了一個(gè)IE,同時(shí),這個(gè)操作不會(huì)返回一個(gè)成功的標(biāo)志,導(dǎo)致開始的Timer以為沒(méi)有瀏覽成功于是繼續(xù)運(yùn)行。  回復(fù)  更多評(píng)論
            


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 庆安县| 东辽县| 资中县| 荥经县| 通山县| 洪泽县| 股票| 丰城市| 临江市| 永州市| 安岳县| 科技| 隆尧县| 宁海县| 溆浦县| 邻水| 湘潭县| 罗江县| 蕉岭县| 美姑县| 镇巴县| 德江县| 徐闻县| 通州市| 浑源县| 晴隆县| 丹江口市| 兰考县| 平山县| 麻城市| 湖南省| 吴江市| 南溪县| 丰镇市| 蓬溪县| 鄯善县| 东莞市| 香格里拉县| 道孚县| 合作市| 公主岭市|