Lo stato dell'array verrà memorizzato nella cache in iOS 12 Safari. È un bug o una funzionalità?


432

Aggiornamento al 2018.10.31

Questo bug è stato corretto in iOS 12.1, buona giornata ~

Ho riscontrato un problema con lo stato del valore dell'array nel Safari iOS 12 appena rilasciato, ad esempio un codice come questo:

<!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>

Dopo aver aggiornato la pagina, il valore dell'array viene ancora invertito. È un bug o una funzionalità del nuovo Safari?


Ecco una pagina dimostrativa. Prova a usarlo con iOS 12 Safari: https://abelyao.github.io/others/ios12-safari-bug.html


41
Bug confermato anche in macOS 10.14 Mojave - i.imgur.com/ZJtJJC1.png
a_rahmanshah

43
macOS 10.13.6 (High Sierra) con Safari Versione 12.0 (13606.2.11) presenta lo stesso problema. L'array è ancora invertito dopo l'aggiornamento della pagina.
Kevin Gimbel,

2
Il bug è stato corretto in Safari 12.0.1 (macOS), così come in iOS 12.1.
MrMister

Risposte:


272

È sicuramente un ERRORE! Ed è un bug molto serio.

Il bug è dovuto all'ottimizzazione degli inizializzatori di array in cui tutti i valori sono letterali primitivi. Ad esempio, data la funzione:

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

Tutti i riferimenti dell'array restituiti dalle chiamate a buildArray()verranno collegati alla stessa memoria e alcuni metodi come i toString()loro risultati verranno memorizzati nella cache. Normalmente, per preservare la coerenza, qualsiasi operazione mutabile su tali array ottimizzati copierà i dati in uno spazio di memoria separato e li collegherà ad essi; questo modello è chiamato copia su scrittura , o CoW in breve.

Il reverse()metodo muta l'array, quindi dovrebbe attivare una copia su scrittura. Ma non è così, perché l'implementatore originale (Keith Miller di Apple) ha perso il reverse()caso, anche se aveva scritto molte prove.

Questo bug è stato segnalato ad Apple il 21 agosto. La correzione è arrivata nel repository WebKit il 27 agosto e spedita in Safari 12.0.1 e iOS 12.1 il 30 ottobre 2018.


11
Nota: Safari 12.0 su Mac OS X presenta anche lo stesso problema.
hax,

17
Sì, è già stato corretto nelle fonti e già spedito in Safari Technology Preview. Prova cdn.miss.cat/demo/ios12-safari-bug.html in Safari Technology Preview 65. Scoprirai che non ha il bug.
sideshowbarker,

6
Non credo che la causa alla base del bug sia il risultato di una confusione dell'indice; invece, sembra essere causato trascurando di controllare se un oggetto è immutabile prima di modificarlo. Il problema della sezione potrebbe avere una spiegazione simile, ma non è la stessa, ma non sarà risolto dalla patch per il contrario, per quanto ne so. Si consiglia di aprire un report di bug WebKit per il problema della sezione.
Zenexer,

5
@Zenexer Hai ragione. Ho scritto questa risposta prima di trovare bugs.webkit.org/show_bug.cgi?id=188794 e vedere il codice sorgente. Modificherò la mia risposta.
hax,

75

Ho scritto una lib per correggere il bug. https://www.npmjs.com/package/array-reverse-polyfill

Questo è il codice :

(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
Aggiorna in qualsiasi momento. Benvenuto per contribuire.
Edire Fan,

14
@zephi, suppongo che scrivere su length ( this.length = this.length) attiverà Copia su scrittura, quindi cambierà l'indirizzo di memoria dell'array e risolverà il comportamento di reverse.
Cœur

14

Questo è un bug nel webkit . Anche se questo è stato risolto alla fine, ma non è ancora stato fornito con iOS GM Release. Una delle soluzioni a questo problema:

(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

Sembra non essere memorizzato nella cache se il numero di elementi cambia.
Sono stato in grado di evitarlo in questo modo.

<!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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.