Dizi durumu iOS 12 Safari'de önbelleğe alınır. Bir hata veya özellik mi?


432

2018.10.31 güncellemesi

Bu hata iOS 12.1'de düzeltildi, iyi günler ~

Yeni yayınlanan iOS 12 Safari'de Array'ın değer durumu ile ilgili bir sorun buldum, örneğin, böyle bir kod:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>iOS 12 Safari bugs</title>
    <script type="text/javascript">
    window.addEventListener("load", function ()
    {
        let arr = [1, 2, 3, 4, 5];
        alert(arr.join());

        document.querySelector("button").addEventListener("click", function ()
        {
            arr.reverse();
        });
    });
    </script>
</head>
<body>
    <button>Array.reverse()</button>
    <p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>

Sayfayı yeniledikten sonra, dizinin değeri hala tersine çevrilir. Bu bir hata mı yoksa yeni Safari'nin bir özelliği mi?


İşte bir demo sayfası. İOS 12 Safari ile kullanmayı deneyin: https://abelyao.github.io/others/ios12-safari-bug.html


41
Hata macOS 10.14 Mojave'de
a_rahmanshah

43
Safari Sürüm 12.0 (13606.2.11) ile macOS 10.13.6 (High Sierra) da aynı sorunu yaşıyor. Sayfa yenilendikten sonra dizi hala tersine çevrilir.
Kevin Gimbel

2
Hata, Safari 12.0.1'de (macOS) ve iOS 12.1'de düzeltildi.
BayMister

Yanıtlar:


272

Kesinlikle bir HATA! Ve bu çok ciddi bir hata.

Hata, tüm değerlerin ilkel değişmezler olduğu dizi başlatıcılarının optimizasyonundan kaynaklanmaktadır. Örneğin, işlev verildiğinde:

function buildArray() {
    return [1, null, 'x'];
}

İçin yapılan aramalardan döndürülen tüm dizi başvuruları buildArray()aynı belleğe bağlanır ve bunun gibi bazı yöntemler toString()sonuçları önbelleğe alınır. Normal olarak, tutarlılığı korumak için, bu tür optimize edilmiş diziler üzerindeki herhangi bir değiştirilebilir işlem, verileri ayrı bir bellek alanına kopyalar ve ona bağlar; bu desene yazma üzerine kopyalama veya kısaca CoW denir.

reverse()Yöntem mutasyon dizisi, bu yüzden bir kopyasını üzerinde yazma tetiklemesi. Ama öyle değil, çünkü orijinal uygulayıcı (Apple'dan Keith Miller) reverse(), birçok testcas yazmış olmasına rağmen davayı kaçırdı .

Bu hata 21 Ağustos'ta Apple'a bildirildi . Düzeltme 27 Ağustos'ta WebKit deposuna indi ve 30 Ekim 2018'de Safari 12.0.1 ve iOS 12.1'de gönderildi.


11
Not: Mac OS X'te Safari 12.0 da aynı soruna sahiptir.
hax

17
Evet, kaynaklarda zaten düzeltildi ve Safari Teknoloji Önizlemesi'nde zaten gönderildi. Safari Technology Preview 65'deki cdn.miss.cat/demo/ios12-safari-bug.html dosyasını deneyin. Hataya sahip olmadığını göreceksiniz.
sideshowbarker

6
Ben hata altta yatan nedeni bir dizin toplama sonucu olduğuna inanmıyorum; bunun yerine, bir nesnenin değiştirilmeden önce değişmez olup olmadığını kontrol etmeyi ihmal etmekten kaynaklanıyor gibi görünmektedir. Dilim sorununun benzer bir açıklaması olabilir, ancak aynı değil ama söyleyebildiğim kadarıyla yama için tersine düzeltilmeyecek. Dilim sorunu için bir WebKit hata raporu açmayı düşünmelisiniz.
Zenexer

5
@Zenexer Haklısın. Bu yanıtı bugs.webkit.org/show_bug.cgi?id=188794 bulmadan ve kaynak kodunu görmeden önce yazdım . Cevabımı düzenleyeceğim.
hax

75

Hatayı gidermek için bir lib yazdım. https://www.npmjs.com/package/array-reverse-polyfill

Bu kod :

(function() {
  function buggy() {
    var a = [1, 2];
    return String(a) === String(a.reverse());
  }
  if(!buggy()) return;
  var r = Array.prototype.reverse;
  Array.prototype.reverse = function reverse() {
    if (Array.isArray(this)) this.length = this.length;
    return r.call(this);
  }
})();


4
İstediğiniz zaman güncelleyin. Katkıya hoş geldiniz.
Edire Fan

14
@zephi, sanırım length ( this.length = this.length) üzerine yazma, Copy On Write'ı tetikleyecektir, bu yüzden dizinin bellek adresini değiştirecek ve böylece davranışını düzeltecektir reverse.
Cur

14

Bu webkit bir hata . Bu sonunda çözüldü, ancak henüz iOS GM sürümü ile gönderilmedi. Bu sorunun çözümlerinden biri:

(function() {
  function getReverseStr() {
    return [1, 2].reverse();
  }

  var n1 = getReverseStr()[0];
  var n2 = getReverseStr()[0];
  // check if there is an issue
  if(n1 != n2) {
    var origReverseFunction = Array.prototype.reverse;
    Array.prototype.reverse = function() {
      var newArr = this.slice();
      // use original reverse function so that edge cases are taken care of
      origReverseFunction.apply(newArr, arguments);
      var that = this;
      // copy reversed array
      newArr.forEach(function(value, index) {
        that[index] = value;
      });
      return this;
    }
  }
})();

6

Eleman sayısı değişirse önbelleğe alınmamış gibi görünüyor.
Bundan böyle kaçınabildim.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>iOS 12 Safari bugs</title>
    <script type="text/javascript">
    window.addEventListener("load", function ()
    {
        let arr = [1, 2, 3, 4, 5];
        arr.push('');
        arr.pop();
        alert(arr.join());

        document.querySelector("button").addEventListener("click", function ()
        {
            arr.reverse();
        });
    });
    </script>
</head>
<body>
    <button>Array.reverse()</button>
    <p style="color:red;">test: click button and refresh page, code:</p>
</body>
</html>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.