Automatyczne sortowanie JSON przez Operę i Chrome

2011-09-27 16:26:30
 

Niedawno napotkałem na dość ciekawy problem. Pobierałem sobie ajaxem dane w postaci JSON a następnie wyświetlałem je w takiej kolejności, w jakiej otrzymałem. Jednak pewnego dnia klient zgłosił mi błąd, że dane wyświetlają się odwrotnie pod Chrome. Jak się później okazało podobny problem był również z Operą. A by przedstawić Wam dokładnie problem, pokażę przykładowy kod i dane, które powodują błąd.

Kod js:

1
2
3
4
5
6
7
8
$.ajax({
  url: 'testjs.php',
  dataType : 'json',
  success: function( data ) {
    for (var i in data) alert(i);
  }
});

oraz plik testjs.php

1
2
3
4
<?php
$ar 
= array(3=>'bla',2=>'ola',1=>'costam');
echo 
json_encode($ar);
?>

Jak widzicie, plik testjs.php generuje mi dane w kolejności 3,2,1. Niestety Opera i Chrome odbiera te dane w kolejności posortowanej 1,2,3. FireFox czy też IE nie sortują danych.

Rozwiązaniem tej sytuacji okazało się niestosowanie indeksów numerycznych tylko tekstowych, np.

1
2
3
4
<?php
$ar 
= array('c3'=>'bla','c2'=>'ola','c1'=>'costam');
echo 
json_encode($ar);
?>

Zamiast literki 'c' można wstawić dowolny tekst. Jeśli jednak ktoś z różnych przyczyn nie może zrobić takiego obejścia, to pozostaje jedynie sortowanie danych w js.

 

Komentarze

 

2011-09-27 21:24:10 gość_szagi3891

 
Rany, co za kicha.

2011-09-28 08:14:44 gość_Bartek

 
Przecież dane JSON są z założenia danymi NIEUPORZĄDKOWANYMI, więc nigdy nie masz pewności w jakiej kolejności je otrzymasz, a co za tym idzie, w jakiej je wyświetlisz. Żeby mieć 100% pewności, zawsze musisz posortować dane po stronie JS.

2011-09-28 08:32:42 nospor

 
Przyznam szczerze iż pierwszy raz słyszę o takim założeniu i mocno mnie ono dziwi/smuci. Wcześniej używałem XML ale odkąd poznałem JSON uznałem to za lepszą alternatywę dla XML. Założenie o nieuporządkowaniu psuje tę "lepszość"

2011-09-28 08:48:29 gość_Bartek

 
Polecam: http://json.org/json-pl.html - i cytat dla leniwych: "Obiekt jest nieuporządkowanym zbiorem par nazwa/wartość. Opis obiektu rozpoczyna { (lewa klamra) a kończy } (prawa klamra). Po każdej nazwie następuje : (dwukropek) oraz pary nazwa/wartość, oddzielone , (przecinkiem)."

2011-09-28 09:14:24 nospor

 
W linku co podałeś mamy też:
Tabela jest uporządkowanym zbiorem wartości. Opis tabeli rozpoczyna znak [ (lewy nawias kwadratowy) a kończy znak ] (prawy nawias kwadratowy). Poszczegóne wartości rozdialane są znakiem , (przecinek).
Czyli, żeby JSON był w takiej kolejności jaki ma być, to należy przekazywać mu dane w postaci tabeli a nie obiektu. Czyli u mnie to by miało być:
1
2
3
<?php
$ar 
= array('bla','ola','costam');
?>

Ale wówczas tracę informacje na temat indeksów. Należy więc wówczas indeksy przenieść do wartości, tworząc poprostu tablicę w wartościach. I to też jest w sumie dobre rozwiązanie problemu. Trzeba tylko o tym pamiętać.

2011-09-28 09:18:31 nospor

 
W zasadzie sądziłem, że gdy podaję indeksy numeryczne, to automatycznie jest tworzona tablica JSON a nie obiekt. Nie zwróciłem uwagi na to, że jednak taki JSON jest z { a nie [. Nauczka na przyszłość

2011-09-28 09:18:41 gość_B3k

 
Nie do końca zgadzam się z podanym rozwiązaniem i tezą problemu.

Niedawno też miałem identyczny problem, jednak musisz przyjrzeć się też funkcji json_encode(), która w przypadku tablic nieasocjacyjnych zwraca ci tablicę, która jest już zbiorem posortowanym wg. klucza. Aby wymusić na json_encode() aby zwracał zawsze obiekt należy użyć opcji JSON_FORCE_OBJECT.

2011-09-28 09:34:50 nospor

 
No właśnie nie. json_encode mi nic nie sortuje. Jak daję tak ono zwraca. dopiero decodowanie JSON w js powoduje sortowanie.

2011-09-28 09:48:35 gość_Bartek

 
Dodam jeszcze, że nie powinieneś używać konstrukcji for(elem in array) {...} do iterowania po elementach tablicy. Tej konstrukcji używaj tylko do iterowania po obiektach. Do iterowania po tablicy używaj: for(i, len = array.length; i < len; i++){...}. Źródło: http://javascript.crockford.com/code.html, sekcja: Statements -> for statement. Dlaczego tak? A no dlatego, że gdy dodasz sobie metodę do tablicy: Array.prototype.mojaWypasionaMetoda = function(){...} to może się zdarzyć, że w pętli for będziesz iterował również po tej metodzie, a tego byś nie chciał.

2011-09-28 10:01:54 nospor

 
Tak, wiem o tym. Ale ja nie dodaję metod do tablic
Poza tym problem który opisałeś równie dobrze może wystąpić w obiektach. Jak dodam metodę do obiektu to też w iteracji pojawi mi się raczej ta metoda.

2011-09-28 18:28:50 gość_B3k

 

No właśnie nie. json_encode mi nic nie sortuje. Jak daję tak ono zwraca. dopiero decodowanie JSON w js powoduje sortowanie.

Zgadza się, json_encode() nic nie sortuje. Ale jeśli przyjrzysz się działaniu tej funkcji to dowiesz się ,że wstawienie tablicy(PHP) nieasocjacyjnej do json_encode(), spowoduje że otrzymasz javascriptową tablicę - która już jest sortowana.

2011-09-28 18:30:31 gość_B3k

 
Nawiązując do mojego porpzedniego posta:
.. która już jest sortowana.

Oczywiście sortuje ją JavaScript po stronie przeglądarki.

2011-09-29 08:00:01 nospor

 
No tak, przecież już od paru postów była o tym mowa, a ty znowu o tym samym piszesz

Dodaj komentarz

 

Dostępne bbcode: b, u, i, color, size, quote, img, url, list, il (tylko w list), code, php, css, html, sql, js