原生andriod瀏覽器回退后dom(click)事件全體失效問題探究


問題描述

今天同事遇到一個神一樣的BUG:

在原生瀏覽器下,為dom元素綁定一個click事件,其中有個a標簽外鏈,點擊a后進入其他頁面,點擊瀏覽器后退后,頁面點擊事件全體失效!

我於是用ios測了下沒事,用andriod其他瀏覽器試了下也沒事,就是原生的有問題,懷疑是特定的手機有問題,又陸續換了幾台,發現原生的都有問題

於是便開始找解決方案,下面就來聊下今天的漫長之路,這里先給會出問題的代碼:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <meta charset="utf-8" />
 5   <title></title>
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 7 </head>
 8 <body>
 9   <div id="ttt">
10     ttt</div>
11   <br />
12   <a href="http://www.baidu.com" name="n">百度一下</a>  
13   <script type="text/javascript">
14       var i = 0;
15       var appendDiv = function (msg) {
16           var div = document.createElement('div');
17           if (msg) {
18               div.innerHTML = msg;
19           } else {
20               div.innerHTML = i++;
21           }
22           document.body.appendChild(div);
23       };
24       document.addEventListener('click', function (e) {
25           appendDiv('click')
26       });
27   </script>
28 </body>
29 </html>

DOM事件丟失

第一步想到的當然是事件丟失了,或者就是不執行了,於是乎寫了一段代碼:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <meta charset="utf-8" />
 5   <title></title>
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 7 </head>
 8 <body>
 9   <div id="ttt">
10     ttt</div>
11   <br />
12   <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13   <script type="text/javascript">
14       var i = 0;
15       
16       setInterval(function () {
17           var div = document.createElement('div');
18           div.innerHTML = i++;
19           document.body.appendChild(div);
20 
21           var type = 'click'; //要觸發的事件類型
22           var event = document.createEvent('MouseEvents');
23           event.initMouseEvent(type);
24           document.dispatchEvent(event);
25 
26       }, 1000);
27       var appendDiv = function (msg) {
28           var div = document.createElement('div');
29           if (msg) {
30               div.innerHTML = msg;
31           } else {
32               div.innerHTML = i++;
33           }
34           document.body.appendChild(div);
35       };
36       document.addEventListener('click', function (e) {
37           appendDiv('click')
38       });
39   </script>
40 </body>
41 </html>

我定時器不停地向瀏覽器打印數字,而且觸發document的click事件,他工作的蠻好的,但是當我點擊百度一下再回來時候,便不執行了

因為我們沒法在代碼層面上獲取dom的事件信息,所以暫時只能這樣做,而我的判斷是,沒錯!dom事件丟失了

Window事件未丟失

然后我又在這上面糾纏了好久,想試試windows的事件是否丟失,於是寫下了以下代碼:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <meta charset="utf-8" />
 5   <title></title>
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 7 </head>
 8 <body>
 9   <div id="ttt">
10     ttt</div>
11   <br />
12   <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13   <script type="text/javascript">
14       var i = 0;
15       
16       setInterval(function () {
17           var div = document.createElement('div');
18           div.innerHTML = i++;
19           document.body.appendChild(div);
20 
21           var type = 'click'; //要觸發的事件類型
22           var event = document.createEvent('MouseEvents');
23           event.initMouseEvent(type);
24           document.dispatchEvent(event);
25 
26       }, 1000);
27       var appendDiv = function (msg) {
28           var div = document.createElement('div');
29           if (msg) {
30               div.innerHTML = msg;
31           } else {
32               div.innerHTML = i++;
33           }
34           document.body.appendChild(div);
35       };
36       document.addEventListener('click', function (e) {
37           appendDiv('click')
38       });
39 
40       window.onresize = function () {
41           appendDiv('onresize')
42       }
43   </script>
44 </body>
45 </html>

我點擊回來后,發現事件還在,於是陷入深深的沉思.沉思.沉思.思.思.思.............

問題解決

最后我無意間將這個問題解決了,而且解決的方案匪夷所思:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <meta charset="utf-8" />
 5   <title></title>
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 7 </head>
 8 <body>
 9   <div id="ttt">
10     ttt</div>
11   <br />
12   <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13   <script type="text/javascript">
14        var t = document.getElementById('ttt'); 15       var i = 0;
16       setInterval(function () {
17           var div = document.createElement('div');
18           div.innerHTML = i++;
19           document.body.appendChild(div);
20       }, 1000);
21       var appendDiv = function (msg) {
22           var div = document.createElement('div');
23           if (msg) {
24               div.innerHTML = msg;
25           } else {
26               div.innerHTML = i++;
27           }
28           document.body.appendChild(div);
29       };
30       document.addEventListener('click', function (e) {
31           appendDiv('click')
32       });
33   </script>
34 </body>
35 </html>

整個解決方案耗費我兩個多小時,而最終卻是這么一段不起眼的代碼:

var t = document.getElementById('ttt');
// var btnfree = document.getElementsByTagName('a'); 無效
// var n = document.getElementsByName('name');無效

現在問題是解決了,我卻更疑惑了,一個大大的問號在我腦里回旋不去,尼瑪在玩我啊......這是為什么??????

問題原理猜想

注意,此處完全是扯淡時間

andriod硬件加速

andriod原生瀏覽器本身使用了硬件加速功能,或者說andriod對自身的瀏覽器做了很好的處理

我們在頁面上看到的頁面具有一個dom樹,而我們的事件js保存在另一個地方,而此時硬件加速為我們提供了一個類似png的中間件

他負責了通訊,但是在我們該網頁轉入后台時,這之間的映射關系卻被破壞了

而我們js代碼中若是多了這么一段代碼:

var t = document.getElementById('ttt');

他的映射關系又建立起來了,如果是這樣的話,是說的過去的!!!

PS:以上的理論顯然無法說服我

垃圾回收/后台掛起

不得已的情況下,我想到了js的垃圾回收,dom結構活生生的在頁面上,頁面不會回收,里面的i一直在用也不會回收

但是我們的DOM樹好像並沒有神引用在頁面中保存,因為沒有瀏覽器就正好將所有的事件全部銷毀了。

而后面我們在js中保存了一個dom樹,他就沒有銷毀????

PS:這里我可以將t給delete了試試,但是我在家沒有環境,只得明天再試了,今天暫時到這里

問題追蹤

var t = document.getElementById('ttt');
t = null;

最后這樣加一句,問題又會復現,所以垃圾回收的概率較高。

結語

當然,這是andriod瀏覽器本身一個BUG,但是如果我們可以從這種小BUG中發現大問題,或者原理性的東西,那真的該好好的研究一番了!!!

若是您有任何想法,請不吝賜教!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM