1. 程式人生 > >iOS 12 safari 的 JS 引擎 reverse 現驚天 bug,或波及整個網際網路

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. <scriptsrc="//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