zoukankan      html  css  js  c++  java
  • 原生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中发现大问题,或者原理性的东西,那真的该好好的研究一番了!!!

    若是您有任何想法,请不吝赐教!!!

  • 相关阅读:
    noip不知道哪年 货车运输
    bzoj1002轮状病毒
    bzoj1001狼抓兔子
    20171002模拟赛
    20171001模拟赛
    异常
    springmvc-servlet.xml 第二种选择
    springmvc入门
    springmvc-servlet.xml(springmvc-servlet.xml 配置 增强配置)
    777
  • 原文地址:https://www.cnblogs.com/yexiaochai/p/3498650.html
Copyright © 2011-2022 走看看