为什么Safari页面会破坏iOS渲染?

Cri*_*sty 79 javascript iphone safari artifacts ios

我知道标题不是那么解释,但这是故事:我正在开发一个浏览器游戏,主要使用JavaScript和Mapbox库.

在桌面,Android和iOS上一切都运行良好但在iOS上出现一个问题:在让游戏运行几分钟之后,手机突然开始出现图形伪影并显示大部分文本乱码.

以下是一些手机开始的照片: 在此输入图像描述 在此输入图像描述 在此输入图像描述

我的问题是:我的代码究竟是什么导致了这个?内存泄漏?(LE:事实证明它实际上是一个内存泄漏)
真正的问题是:你怎么能通过浏览网页几乎把整个手机搞得一团糟?Safari不应该停止这个,或者至少是iOS吗?

这不是这个特定设备的问题,因为这个问题可以在不同的iPhone设备上重现.(我对不同的iOS版本不太确定).

我如何重现错误:

  1. 打开游戏(在Safari中).
  2. 让它运行3-4分钟.
  3. 向下滑动通知中心,一切都变得疯狂.
    我添加了一段YouTube视频,展示了如何重现错误(在我的iPhone 5C上).
    似乎问题首先出现在通知中心(如果您从顶部向下滑动菜单).
    至于现在,这个问题似乎只发生在iPhone 5CiOS 9.2.1(13D15)上.它也出现在新的iOS 9.3版本上.

为了解决这个问题,我必须:

  1. 关闭Safari应用程序(游戏选项卡打开).
  2. 锁定手机.解锁后一切恢复正常.

关于游戏本身的一些细节:

  1. 游戏显示一个Mapbox地图和一些单位(标记).
  2. Node.js服务器以1滴/秒的速度运行,每次滴答后,更新的游戏状态通过Socket.io发送到浏览器.
  3. 每次浏览器收到游戏状态时,它都会相应地更新标记.
  4. *如果您放大或缩小或者选择它们,游戏也可能会更新标记.

EDIT2: 发现内存泄漏(如预期).修复此泄漏(检查undefined_icon)后,问题不再发生.这意味着,在这些行的某处,触发了Safari/iOS错误.

对于每个聚类的单元(隐藏在MarkerCluster中并与其他单元组合在一起),以下是每个tick的确切调用内容:

    var $icon = $(marker._icon); // marker._icon is undefined because of the clustering

    $icon.html('');

    $icon.append($('<img class="markerIcon" src="' + options.iconUrl + '" />'));

    var iconX = 10;
    var iconY = -10;
    var iconOffset = 0;

    for(var v in this.icons) {
        this.icons[v].css('z-index', + $icon.css('z-index') + 1);
        this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                                + (iconY + iconOffset) + 'px,' + '0px)');
        iconOffset += 20;

        this.icons[v].appendTo($icon);
    }

    // Fire rate icons
    this.attackRateCircle = $('<div class="circle"></div>');
    this.attackRateCircle.circleProgress({
        value: 0,
        size: 16,
        fill: { color: "#b5deff" },
        emptyFill: 'rgba(0, 0, 0, 0.5)',
        startAngle:  -Math.PI / 2,
        thickness: 4,
        animation: false,
    });
    this.attackRateCircle.hide();

    // Create and display the healthbar
    this.healthBar = $('<div>').addClass('healthBar ');
    this.healthBar.css('z-index', $icon.css('z-index'));
    this.healthBarFill = $('<span class="fill">');
    this.healthBar.append(this.healthBarFill);

    $icon.append(this.healthBar);
    $icon.append(this.attackRateCircle);
Run Code Online (Sandbox Code Playgroud)

这是icons阵列:

this.icons = {
    attack_order: $('<img src="img/attack.png" class="status_icon">'),
    attack: $('<img src="img/damage.png" class="status_icon icon_damage">'),
    hit: $('<img src="img/hit.png" class="status_icon icon_hit">'),
};
Run Code Online (Sandbox Code Playgroud)

circleProgress来自这个库的电话:https://github.com/kottenator/jquery-circle-progress

DEMO

是的,我已经能够创建一个重现错误的jsFiddle:https://jsfiddle.net/cte55cz7/14/ 在iPhone 5C上的Safari上打开并等待几分钟.在iPhone 6和iPad mini上页面崩溃(正如预期的那样由于内存泄漏)

这是HasteBin中的相同代码,适用于任何不想运行它的人.

A S*_*ANI 1

这种内存泄漏可能是由于“WebKit\xe2\x80\x99s JS Engine\”的工作方式造成的 [safari webkit-javascript llvm]

\n\n

看起来确实像是虚拟内存缓冲区溢出,对剩余 RAM 有直接影响(iOS 也共享和使用它来存储用户界面图形元素)

\n\n

相对于这段代码:\n"[...]查找 jQuery 内存泄漏很容易。检查 $.cache 的大小。如果 \xe2\x80\x99s 太大,请检查它并查看哪些条目保留以及原因.[...]”(http://javascript.info/tutorial/memory-leaks

\n\n

让我期待它与这个for 循环相关:

\n\n
for(var v in this.icons) {\n    this.icons[v].css(\'z-index\', + $icon.css(\'z-index\') + 1);\n    this.icons[v].css(\'transform\', \'translate3d(\' + iconX + \'px,\' \n                            + (iconY + iconOffset) + \'px,\' + \'0px)\');\n    iconOffset += 20;\n\n    this.icons[v].appendTo($icon);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

假设检查已完成,并且还假设您找到了条目,您可能需要使用removeData()手动清理数据,也可以先使用$elem.detach(),然后放置$(elem).remove( )在 setTimeout 中。

\n