iOS 12 safari 的 JS 引擎 reverse 现惊天 bug,或波及整个互联网

虽然 iOS 12 的发布,很多人都升级了最新版,感觉确实快了不少。

但是昨天有人在 stackoverflow 发现了一个问题:

 
  
  1. let arr = [1, 2, 3, 4, 5];

  2. alert(arr.join());

  3. document.querySelector("button").addEventListener("click", function (){

  4.  arr.reverse();

  5. });

使用 reverse 函数将一个数组翻转,但是当重新刷新页面后,原数组依然是翻转的。不知道是 Safari 的 bug 还是 feature。

随后前端元老贺师俊(@johnhax)给出了一个可能的原因:

iOS 12 safari 的 JS 引擎 reverse() 惊天大 bug 之原因分析:Safari 对所有值是 primitive literal 的 array initializer 做了优化,同一个 initializer 产生的数组在内存里永远指向一份, reverse() 之后,所有从这个 initializer 得到的数组也都倒序了。


另一方面,其 toString() 的结果是预先计算缓存的,所以 toString() 结果并不会修改。按正常优化来说,如果某个这样的 array 执行了任何修改操作,应该复制到一份独立内存去。这是所谓 copy-on-write 的策略。但不幸的, reverse() 方法没有触发 CoW。


另一方面,所有不修改 array 的方法应该不触发 CoW。我实测下来,甚至 copyWithin 和 fill 这样的方法,如果 start/end 相同使得实际上并没有修改效果,也不会触发 CoW。


但是神奇的是 slice() 会触发 CoW。所以我猜有可能某个苹果的临时工把 reverseslice 的方法索引搞颠倒了。

昨天晚上明非(@fanmingfei)同学通宵写了一个 npm 包来解决这个问题 https://github.com/fanmingfei/array-reverse-ios12

并于凌晨 4 点将此包发布到了 npm,睡了 2 个小时的他今天又继续修复了几处 bug。

CDN 使用:

 
  
  1. <script src="//g.alicdn.com/mtb/fix-ios12-array/1.0.8/index.js"></script>

NPM 使用:

 
  
  1. import 'array-reverse-polyfill'

希望苹果早日修复此 bug。

最后,附一张贺老给这个库做的 logo。

640?wx_fmt=png


猜你喜欢

转载自blog.csdn.net/vCa54Lu0KV27w8ZZBd/article/details/82783060
今日推荐