javascript - El estado de la matriz se almacenará en caché en iOS 12 Safari. ¿Es un error o característica?
ios12 (4)
¡Definitivamente es un ERROR! Y es un error muy serio.
El error se debe a la optimización de los inicializadores de matriz en los que todos los valores son literales primitivos. Por ejemplo, dada la función:
function buildArray() {
return [1, null, ''x''];
}
Todas las referencias de matriz devueltas de las llamadas a
buildArray()
se vincularán a la misma memoria, y algunos métodos como
toString()
tendrán sus resultados en caché.
Normalmente, para preservar la coherencia, cualquier operación mutable en dichas matrices optimizadas copiará los datos en un espacio de memoria separado y se vinculará a ellos;
este patrón se llama
copy-on-write
o CoW para abreviar.
El método
reverse()
muta la matriz, por lo que debe activar una copia en escritura.
Pero no es así, porque el implementador original (Keith Miller de Apple) se perdió el caso
reverse()
, a pesar de que había escrito muchos casos de prueba.
Este error fue reportado a Apple el 21 de agosto. La solución llegó al repositorio de WebKit el 27 de agosto y se envió a Safari 12.0.1 y iOS 12.1 el 30 de octubre de 2018.
Actualización a 2018.10.31
Este error se ha corregido en iOS 12.1, ten un buen día ~
Encontré un problema con el estado de valor de Array en el recientemente lanzado iOS 12 Safari, por ejemplo, un código como este:
<!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>
Después de actualizar la página, el valor de la matriz aún se invierte. ¿Es este un error o una característica del nuevo Safari?
Aquí hay una página de demostración. Trate de usarlo con iOS 12 Safari: https://abelyao.github.io/others/ios12-safari-bug.html
Escribí una lib para arreglar el error. https://www.npmjs.com/package/array-reverse-polyfill
(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);
}
})();
Este es un error en el webkit . Aunque esto se ha resuelto al final, pero aún no se ha enviado con el lanzamiento de iOS de iOS. Una de las soluciones a este 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;
}
}
})();
Parece que no se almacena en caché si cambia el número de elementos.
Pude evitar esto así.
<!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>