首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
华为云
V2EX  ›  问与答

iOS 12 的 safari 有哪些变化吗?今天发现了一个 javascript 的问题

  •  7
     
  •   34C · 61 天前 · 4227 次点击
    这是一个创建于 61 天前的主题,其中的信息可能已经有所发展或是发生改变。

    正在开发的程序中,有一段代码大概如下:

    window.addEventListener("load", function ()
    {
        var arr = [1, 2, 3, 4];
        arr.reverse();
    });
    

    今天升级了 iOS 12 之后,无意中发现数组的顺序有问题。

    第一次加载是正常的, 页面刷新会颠倒, 再刷新又正常了, 再刷新又颠倒了, 以此类推…

    而如果是关闭了页面、重新打开,则不会有问题。

    在 PC Chrome / Android / iOS 11 Safari 中都没出现这个问题,就好像这个变量,被 safari “缓存” 了一样,即使刷新页面也会被保留、继承之前的状态。

    这是 iOS 12 Safari 的 bug 还是 feature 啊?有没有哪里可以看到关于 safari 底层机制的改变呢?

    第 1 条附言  ·  61 天前
    测试了一下,代码改成 var arr = new Array(1, 2, 3, 4); 之后则没问题,
    难道真的有缓存变量状态的 new feature ?
    原来变流畅的方法就是缓存到内存而不执行…?
    第 2 条附言  ·  61 天前
    做了个测试页,有兴趣的可以试试,https://cdn.miss.cat/demo/ios12-safari-bug.html
    第 3 条附言  ·  60 天前
    stackoverflow 上的网友已经确认了在 macOS 10.14 Mojave 也有相同问题,
    31 回复  |  直到 2018-09-25 23:23:07 +08:00
        1
    uuair   61 天前
    adblock 没法用了。。
        2
    34C   61 天前
    @uuair 求帮顶,如果这个 “ feature ” 真的存在,那依赖 js 变量做状态的(比如 var userinfo 之类的),要出很多大坑了
        3
    34C   61 天前
    经测试,改成 var arr = new Array(1, 2, 3, 4); 之后则没问题,稍后 append 到主题中。
    看样子如果不是明确 new 的话是会被缓存了……
        4
    gkiwi   61 天前
    @34C 找人测试了,果然如此,这个世界要爆炸。。
        5
    34C   61 天前
    @gkiwi 想象一下有多少人升级 12 而不会升级 12.1 的,如果是 bug 以后即便修复了也会有人一直受影响,如果是 feature 这特么也太严重了,多少项目多少代码会受影响,还有 npm 上那些被数千万项目引用的包…
        6
    gkiwi   61 天前
    @34C #5 定性肯定是 bug。我这边测试不加 load,直接 alert 出来数据都偶发不对。
    一方面浏览器修,二方面就是靠 pollify 了
        7
    34C   61 天前
    @gkiwi 我这边测试是 load 事件都会触发,但 load 中申明的变量,有概率会被缓存,太坑了,还好项目开发了一半,有改语法的机会
        8
    yinanc   61 天前 via iPhone
    mark
    前端日常骂娘时间
        9
    34C   61 天前
    @yinanc 顶上去让更多人看到,V2 上前端还蛮多的
        10
    yinanc   61 天前 via iPhone
    @34C 真是这么严重的问题的话很快就会有轩然大波了。不如自己先去确认下吧。
        11
    34C   61 天前
    @yinanc 所以我的标题是问有哪些变化啊… 因为我这是小项目,也没提前升级测试版 iOS 12,所以来问问看苹果之前有没有公开说明过 safari 会有那些改动啊,除了苹果官方的说明是一种 “确认” 我不知道还能怎么自己先确认了,我和楼上的都测试过可以复现问题,难道是我对 js 的工作机制理解有误… 那 ios 11 和 chrome 之类的都没问题啊…
        12
    edire   60 天前
    写了个文件修复这个问题:

    https://www.npmjs.com/package/fix-array-reverse

    https://github.com/fanmingfei/array-reverse-ios12

    目前发现只有使用 reverse 才会缓存,另外,不知道苹果是否会热更新修复这个问题。
        13
    edire   60 天前
    npm 现在限制实在太多了。本来想 npm unpublish 一下再 publish,告诉我 24 小时之内不能 publish 索性改了个名字 https://www.npmjs.com/package/array-reverse-polyfill
        14
    Trim21   60 天前 via Android
    成功复现…
        15
    hax   60 天前   ♥ 6
    这显然是一个 bug。并且是个惊天大 bug。

    此 bug 跟 load 事件无关。直接执行即可重现。与刷新也并不直接相关。
    简化的测试代码见: https://github.com/hax/hax.github.com/blob/master/browser-bugs/ios12-safari-array-reverse/test.html
    测试页面链接: https://johnhax.net/browser-bugs/ios12-safari-array-reverse/test


    此 bug 的本质是,Safari 对所有值是 primitive literal (如 null, true, 1, 'x' 是,但 /x/,undefined、NaN 就不是)的 array initializer 做了优化,同一个 initializer 产生的数组在内存里永远指向一份,其 toString 的结果也预先计算好,所以 reverse()之后 toString()结果不变,但实际数组已经变化。正常来说,如果该 array 执行了任何修改操作,则复制到一份独立内存去。这是所谓 copy-on-write 的优化策略。但不幸的,reverse 方法没有触发 CoW。

    另一方面,所有不修改 array 的方法应该不触发 CoW。我实测下来,甚至 copyWithin 和 fill 这样的方法,如果 start/end 相同使得实际上并没有修改效果,也不会触发 CoW。但是神奇的是 slice()会触发 CoW。所以我猜有可能某个苹果的临时工把 reverse/slice 的方法索引搞颠倒了。
        16
    34C   60 天前 via iPhone
    @edire @hax 原来 SO 上两条回复也是你们啊…
        17
    atian25   60 天前
    @edire 不要 unpublish,直接按 semver 规范发一个 minor 或 patch 就好了
        18
    34D   60 天前
    没我大。
        19
    34C   60 天前 via iPhone
    @34D 你赢了
        20
    oh   60 天前
    @hax 你这个分析并不能解释为什么 safari 为了性能要缓存变量啊,页面都 reload 了内存都不清空,为了性能值得这么冒险吗?那说不定还有其它隐藏 bug 呢
        21
    JayZangwill   60 天前
    这个问题在 qq 浏览器上也能复现
        22
    34C   60 天前
    @JayZangwill ios 上所有浏览器都是基于 safari 内核
        23
    mrcode   60 天前
    @34C @34D 两兄弟很溜
        24
    mrcode   60 天前
    #22 @34C 包括 Chrome、Firefox 这些吗?
        25
    mrcode   60 天前
    这个问题是因为什么导致的呢?
        26
    34C   60 天前 via iPhone
    @mrcode

    firefox 没装过,但 ios 上的 chrome 就是 safari 套了个皮(仅仅指 ios 上的),什么微信啊 QQ 啊 内置的浏览器都一样

    原因见楼上 hax 的分析咯
        27
    hax   60 天前
    @oh 根据源码来看,基本上就是我说的问题(除了 reverse/slice 颠倒的瞎猜之外)。至于说刷新,其实是无关的。估计应该是 safari 在刷新本页的时候,一看啥都没变,就不销毁之前的资源继续用了。实际上不是每次刷新都复用的,有概率全清掉的。
        28
    hax   60 天前
    bug 来源: https://github.com/WebKit/webkit/commit/c02f5d334455d7fe8b16fe642d1f5900c5cde6e9
    修复: https://bugs.webkit.org/show_bug.cgi?id=188794

    是的,上个月 webkit 已经修掉了( 6 月上的 bug 代码),但是 apple 不知道为啥这次发版没把 patch 打上。
        29
    hax   60 天前
    至于为什么要用 CoW,当然就是为了性能啰。在 https://bugs.webkit.org/show_bug.cgi?id=185003 这里有提到在某些性能测试中有显著提升。
    但是 CoW 很复杂,一下改了好多代码,所以出 bug 了。其实当时作者也写了很多 testcase,无奈还是漏掉了 reverse()。
        30
    mrcode   60 天前
    大胆猜测一下 hax 就是那个实习生 (逃
        31
    spiderGgl   54 天前
    兄弟,你吃屎了,这样害我
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   747 人在线   最高记录 3821   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 18ms · UTC 18:34 · PVG 02:34 · LAX 10:34 · JFK 13:34
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1