iOS 12 safari 的 JS 引擎 reverse 現驚天 bug,或波及整個網際網路
雖然 iOS 12 的釋出,很多人都升級了最新版,感覺確實快了不少。
但是昨天有人在 stackoverflow 發現了一個問題:
let arr =[1,2,3,4,5];
alert(arr.join());
document.querySelector("button").addEventListener("click",function(){
arr.reverse();
});
使用 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。所以我猜有可能某個蘋果的臨時工把reverse
/slice
的方法索引搞顛倒了。
昨天晚上明非(@fanmingfei)同學通宵寫了一個 npm 包來解決這個問題 https://github.com/fanmingfei/array-reverse-ios12
並於凌晨 4 點將此包釋出到了 npm,睡了 2 個小時的他今天又繼續修復了幾處 bug。
CDN 使用:
<scriptsrc="//g.alicdn.com/mtb/fix-ios12-array/1.0.8/index.js"
NPM 使用:
import'array-reverse-polyfill'
希望蘋果早日修復此 bug。
最後,附一張賀老給這個庫做的 logo。