2010-07-06 14 views
24

Me di cuenta de que cierto código que evalúa algunos tamaños de zapatos para un sitio de comercio electrónico y los emite en la pantalla está arruinando el orden en Chrome.Chrome reordenando las teclas del objeto si son numéricas, es normal/esperado

JSON dado puede ser:

{ 
    "7": ["9149", "9139", "10455", "17208"], 
    "7.5": ["9140", "9150", "10456", "17209"], 
    "8": ["2684", "9141", "10457", "17210"], 
    "8.5": ["9142", "10444", "10458", "17211"], 
    "9": ["2685", "9143", "10459", "17212"], 
    "9.5": ["10443", "9144", "10460", "17213"] 
} 

... que incrementa tamaños en mitades.

Tras la conversión en un objeto y iterando aunque las llaves, el orden natural se respeta y salen como:

7, 7,5, 8, 8.5 etc.

Pero en cromo solamente, llaves que 'mirar' como números redondos SIEMPRE salen del objeto primero, por lo que la salida de un bucle for ... in es:

7, 8, 9, 7. 5, 8.5, 9.5 ...

Object.keys(sizes); // ["7", "8", "9", "7.5", "8.5", "9.5"] 

Aquí es el caso de prueba: https://jsfiddle.net/wcapc46L/1/

Es sólo afecta a números enteros, parece como Webkit/Blink tiene una optimización que prefiere propiedades de los objetos que se encuentran numérico, tal vez tiene que ver con Branch Prediction o lo que sea.

Si el prefijo las claves de objeto con cualquier carácter, el orden no se ve afectado y funciona como está previsto - FIFO

Creo recordar haber leído que no hay garantías en el orden de propiedades de un objeto, pero al mismo el tiempo, esto es molesto al extremo y causaría una cantidad considerable de esfuerzo en solucionarlo solo para los usuarios de Chrome.

¿Alguna idea? ¿Es probable que se trate de un error que se solucione?

edición, además, he descubierto ahora esto como un problema en el seguimiento de errores v8:

http://code.google.com/p/v8/issues/detail?id=164

Parece que parpadeo no quieren solucionar este problema y seguirá siendo el único navegador que se hazlo.

actualización lo hash de optimización mesa webkit/abrir y cerrar tenía, ahora ha hecho su camino en gecko (FF 27.0.1) - http://jsfiddle.net/9Htmq/ resultados en 7,8,9,7.5,8.5,9.5. aplicando _ antes de que las teclas devuelvan el orden correcto/esperado.

actualización 2017 personas siguen Upvoting y edición de este modo - no parece afectar Map/WeakMap, Set etc (como se demuestra con el ejemplo principal actualizada)

+0

+1 para un caso de prueba. – spender

+4

Creo que debe reorganizar su método de planificación aquí. * Si usted ha leído * que el orden es indefinido, ¿por qué te quejas por tener que arreglar un montón de código cuando se descubre que ahora * * oh sorpresa, que no está definido? Esto no es un error que se fija, otra que decir que el error está en el código, te apoyaste en los detalles de implementación, no en el comportamiento documentado. Arregla tu código –

+1

en el momento del desarrollo, Chrome no estaba cerca y ahora representa el 7% de los usuarios del sitio. hasta que llegó el cromo, funcionó como se esperaba en todos los navegadores, Safari incluido - por lo que no es una cuestión webkit.y sí, entiendo que podría necesitar una refactorización, pero estaba esperando una solución más fácil (o que Chrome realmente arreglará esto como todos los demás). por ahora, puede que tenga que prefijar todas las propiedades del objeto con __ o algo para forzar el orden natural de la definición. –

Respuesta

20

Es la forma v8 maneja matrices asociativas. Un problema conocido Issue 164 pero sigue la especificación, por lo que está marcado como "funciona según lo previsto". No hay un orden obligatorio para el bucle a través de matrices asociativas.

Una solución sencilla consiste en preceder a los valores de número con letras por ejemplo: 'size_7':['9149','9139'] etc.

La norma va a cambiar en la siguiente especificación ECMAScript obligando [Cromo] desarrolladores de cambiar esta situación.

+1

¿cambio a favor de la implementación actual de Chrome o a favor de preservar el orden de definición? –

+2

conservando el orden ya que todos los otros navegadores ya lo hacen. –

+0

noticias increíbles! muchas gracias. –

1

parecería que Chrome está tratando entero cadena como si fuera un tipo numérico cuando se utiliza como un nombre de índice/propiedad.

Creo que confiar en la implementación de Javascript para conservar el orden de lo que, en algunos casos, son propiedades del objeto, y en otros casos (ciertamente con cromo), es una aproximación insegura y el orden de enumeración probablemente no sea definido en la especificación Yo sugeriría añadiendo una propiedad adicional a la JSON que indica un orden de clasificación:

{ 
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]}, 
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]} 
    //etc 
} 
+0

que puede funcionar: puedo aplicar un filtro que comprueba la propiedad sortOrder al realizar un bucle e inyecta los elementos en consecuencia en el DOM. –

0

No creo que se puede llamar a esto un error. Como dices tú mismo, no hay garantía de cómo se ordenan las propiedades de un objeto.

+0

Y esa no es una respuesta. –

1

Están siendo tratados como cadenas porque son cadenas. Mi mejor sugerencia sería usar la misma "precisión" en todas sus claves.

{"7.0":["9149","9139","10455","17208"],"7.5":["9140","9150","10456","17209"],"8.0":["2684","9141","10457","17210"],"8.5":["9142","10444","10458","17211"],"9.0":["2685","9143","10459","17212"],"9.5":["10443","9144","10460","17213"]} 

Así, "8.0" en lugar de "8", etc.

Incluso entonces, no hay garantías, pero es más probable que ellos salen en el mismo orden.

Para una mejor garantía, lleve a cabo una especie en función de las teclas, poner los valores en una matriz en el orden de clasificación.

+0

lamentablemente, aunque esto funcionará para el caso de prueba, esta no será una opción para la implementación. los tamaños son una multitud de varias opciones, como 'S, M, L, XL, XXL 'o '44, 44.5,44.5' o 'Tamaño único', etc., tal como lo define el comerciante por producto. existe una lógica tremenda al ordenar el resultado de MYSQL para que llegue en el orden correcto y no como cadenas; cubre algo así como 40 tamaños diferentes predefinidos en orden de preferencia. –

1

Cuando iterar sobre las propiedades de un objeto, el orden se especifica en la especificación ECMAScript como indefinido y cualquier orden que pueda haber observado en algunos medio ambiente no debe ser tomado como. Si necesita un pedido, use un Array.

0

he encontrado un trabajo fácil torno utilizando underscore.js

myArray = _.sortBy(myArray, function(num){ return Math.ceil(num); }); 

Yay! myArray ha vuelto al orden correcto en todos los navegadores.

Cuestiones relacionadas