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

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

  •  7
     
  •   34C · 2018-09-18 21:09:38 +08:00 · 9657 次点击
    这是一个创建于 2018 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    目前发现只有使用 reverse 才会缓存,另外,不知道苹果是否会热更新修复这个问题。
    edire
        13
    edire  
       2018-09-19 04:44:27 +08:00
    npm 现在限制实在太多了。本来想 npm unpublish 一下再 publish,告诉我 24 小时之内不能 publish 索性改了个名字 https://www.npmjs.com/package/array-reverse-polyfill
    Trim21
        14
    Trim21  
       2018-09-19 05:30:35 +08:00 via Android
    成功复现…
    hax
        15
    hax  
       2018-09-19 06:26:41 +08:00   ❤️ 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 的方法索引搞颠倒了。
    34C
        16
    34C  
    OP
       2018-09-19 09:27:23 +08:00 via iPhone
    @edire @hax 原来 SO 上两条回复也是你们啊…
    atian25
        17
    atian25  
       2018-09-19 11:28:20 +08:00
    @edire 不要 unpublish,直接按 semver 规范发一个 minor 或 patch 就好了
    34D
        18
    34D  
       2018-09-19 13:41:13 +08:00
    没我大。
    34C
        19
    34C  
    OP
       2018-09-19 14:10:23 +08:00 via iPhone
    @34D 你赢了
    oh
        20
    oh  
       2018-09-19 16:42:00 +08:00
    @hax 你这个分析并不能解释为什么 safari 为了性能要缓存变量啊,页面都 reload 了内存都不清空,为了性能值得这么冒险吗?那说不定还有其它隐藏 bug 呢
    JayZangwill
        21
    JayZangwill  
       2018-09-19 16:49:29 +08:00
    这个问题在 qq 浏览器上也能复现
    34C
        22
    34C  
    OP
       2018-09-19 16:57:12 +08:00
    @JayZangwill ios 上所有浏览器都是基于 safari 内核
    mrcode
        23
    mrcode  
       2018-09-19 19:36:47 +08:00
    @34C @34D 两兄弟很溜
    mrcode
        24
    mrcode  
       2018-09-19 19:37:30 +08:00
    #22 @34C 包括 Chrome、Firefox 这些吗?
    mrcode
        25
    mrcode  
       2018-09-19 19:43:36 +08:00
    这个问题是因为什么导致的呢?
    34C
        26
    34C  
    OP
       2018-09-19 19:46:24 +08:00 via iPhone
    @mrcode

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

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

    是的,上个月 webkit 已经修掉了( 6 月上的 bug 代码),但是 apple 不知道为啥这次发版没把 patch 打上。
    hax
        29
    hax  
       2018-09-19 21:17:58 +08:00
    至于为什么要用 CoW,当然就是为了性能啰。在 https://bugs.webkit.org/show_bug.cgi?id=185003 这里有提到在某些性能测试中有显著提升。
    但是 CoW 很复杂,一下改了好多代码,所以出 bug 了。其实当时作者也写了很多 testcase,无奈还是漏掉了 reverse()。
    mrcode
        30
    mrcode  
       2018-09-19 23:00:38 +08:00
    大胆猜测一下 hax 就是那个实习生 (逃
    spiderGgl
        31
    spiderGgl  
       2018-09-25 23:23:07 +08:00
    兄弟,你吃屎了,这样害我
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1265 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 17:53 · PVG 01:53 · LAX 10:53 · JFK 13:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.