Newsgroup: it.comp.lang.javascript
Titolo: Select molto lunghe e memoria insufficiente con IE (lungo)

Ciao
Sto sviluppando un'applicazione intranet che richiede talvolta la 
presenza di tendine moooolto lunghe. Ad esempio i codici dei comuni 
d'Italia, cioè 8100 righe circa.
Volevo ottimizzare il caricamento della tendinona da parte del client, 
facendo in modo che il file fosse presente nella cache.
Per fare questo ho pensato 2 soluzioni, ma entrambe non sono state 
abbastanza:
1) Scrivere un js esterno con un array bidimensionale da caricare in 
testata e mediante una funzione onload popolare un select vuoto mediante 
DOM.
Risultati su Pentium 4 3.0Ghz:
	- Firefox 1.5: 3 sec circa... bene
	- Opera 8.51: 12 sec circa ... ahi, ma il resto della pagina è 
funzionante e non c'è freeze dello schermo
	- IE 6: 68 sec!!! (con pesante freeze dello schermo...) Arghhh...
Allora ho pensato una soluzione 2
2) Scrivo il mio js esterno in testata di pagina, ma stavolta ci scrivo 
una variabile di testo con tutta la tendinona di 8100 opzioni.
Onload mediante funzione faccio un bel innerHTML dentro un <div 
id="target"></div>
Risultati (sempre sul Pentium 4 3.0Ghz):
	- Firefox 1.5: 0.7 secondi... Yeah!
	- Opera 8.51: 0.8 sec... Evvai...
	- IE 6: Crash.. inizia a pompare la memoria virtuale, arriva a 2 giga 
con processore al 100% poi si impasta il computer e funziona tutto un 
po' male.
	Per curiosità: IE 5.5 fa una cosa più saggia, che mi spiega 
indirettamente (forse) quanto successo con IE 6, ossia mi manda una 
[Object Error] con commento di Memoria Insufficiente.
Conclusioni personali.
Che Explorer fosse un browser instabile lo sapevo, ma così tanto non lo 
credevo possibile. Soprattutto mi stupisce che IE 5.5 abbia un 
comportamento più stabile e saggio del 6.
Capisco anche che una tendina di 8000 record sia veramente tanto, ma che 
fare?
Ho provato ad ottimizzare al massimo le mie funzioni, ma il solo 
caricamento (quindi senza processare nulla) di un valore di 8000 righe 
in una variabile manda il sistema in crash.
Devo abbandonare l'idea e sparare la tendina nell'HTML?
Grazie a chi è arrivato a leggere fin qui.
Marcello

 Marcello

Marcello V ha scritto:

8000 record..... e se dividi il tutto per 8? ne avresti 1000 in 8 
blocchi giusto? quindi a secondo del blocco che ti serve lo rendi 
visibile, esempio, metti che hai la tendina che dovrebbe mostrare tutti 
e gli 8000 record, tu cominci col far mostrare i primi 1000, arrivati al 
1000esimo rendi visibile il 2 gruppo e non il primo e cosi via, una 
volta caricati, a renderli visibili ci metti un attimo, figurati poi se 
dividi per blocchi da 100 :) spero di averti dato la soluzione 
appropriata :P

 
Ci ho pensato. Il problema (che non ho descritto, in quanto il mio post 
era già fin troppo lungo) è dato dal contesto: la tendina appare in una 
maschera "astratta" ossia generata in base alla configurazione della 
tabella definita in un DB di regole sul DB dei dati. E' un sistema a mio 
parere interessante e l'applicazione è un frontend web avanzato con 
sistema di diritti per utenti non sviluppatori. Se l'organizzazione per 
cui lavoro non mi crea problemi la rilascerò in GPL.
Ma non posso scremare attraverso la provincia in quanto mi ritrovo un 
campo COMUNE con una chiave esterna del DB (riferimento alla tabella 
comune) che non posso prevedere a priori, a meno di iniziare ad inserire
eccezioni nel codice, cosa che vorrei assolutamente evitare.
La maschera poi avanza tra i record, scrive, modifica e cancella record 
tramite chiamate asincrone (ajax), quindi la pagina la carico una sola 
volta per ogni tabella. Quindi non posso neppure caricare una parte di 
record per volta, in quanto il primo record magari ha un riferimento al 
comune di "Zuglio" (chissà dov'è poi... :-) )

 appropriata :P
Ho pensato qualcosa del genere, ma non saprei come progettarlo...
Posto che il problema c'è con IE, e quindi potrei svolgere la cosa in 
questa maniera son con questo browser, tu come lo progetteresti?
Con un XMLHttpRequest o con una lettura di diverse porzioni di dati?
Ho provato a scrivere in innerHTML diverse parti di tendina per volta ma 
non funziona.
Se gli fai scrivere
<select name="pippo" id="ciao">
	<option value="1">uno</option>
	<option value="2">due</option>
	...
eccetera e poi continui con un secondo blocco in innerHTML
	<option value="3">tre</option>
	<option value="4">quattro</option>
	<option value="5">cinque</option>
</select>
 
i browser (sia IE che Firefox) alla prima scrittura aggiungono da soli 
il </select> mancante e il secondo blocco appare fuori dalla tendina.
boh!
Grazie, per ora...
 

     
bhè, e se usi gli array? tu ti carichi la pagina no? la carichi tutta 
perchè ti servono i record disponibili, bene, ma se li fai salvare su 
array? li puoi richiamare in ogni istante no? io mi ci trovo bene, in 
questo modo con js puoi cambiare i valori del select, magari hai il 
primo gruppo composto da 10 select
<select>
<opt 1>
<opt 2>
..
<opt 10>
</selct>
poi appena arrivi alla <opt 10> js lo rileva perchè ad ogni change, 
manda il valore alla funzione, e se la posizione è = a 10 allora cambia 
i valori, <opt 1> diventa <opt 11> etc.
in questo modo avrai sempre gli stessi identiti <opt > ma con nomi e 
valori differenti. e una tendina lunga solo quanto vuoi tu, non 8000 ma 
ad esempio 10. direi che in velocità cambia :D

 >
basta un get
(on change)
e fai la select ad ogni tasto
la ho fatta e in lan e' una scheggia e i dati passati sono pochi byte
ti passo un esempio (cambia in base a cio che l'utente scrive)
----------------------------------index.html
<html>
<head>
<script src="selectcustomer.js"></script>
</head>
<body>
<form>
Select a Customer:
<input type="text" name="customers" onkeyup="showCustomer(this.value)">
</form>
<div id="txtHint"><b>Customer info will be listed here.</b></div>
</body>
</html>
-----------------------------------------------------getcustomer.php
<?
if(!empty($_GET['q'])){
  if(strlen($_GET['q'])>2){
        $xx = explode(" ", $_GET['q']);
        $uvv = array();
        if(count($xx) > 1){
          $uvv[] = "ut_cognome LIKE '".$xx[0]."%' ";
          $uvv[] = "ut_nome LIKE '".$xx[1]."%' ";
          $part = implode("AND ", $uvv);
        }else{
          $part = "ut_cognome LIKE '".$xx[0]."%' ";
        }
    $sql="SELECT * FROM user_ospiti_registrati WHERE ".$part." LIMIT 0,
15;";
echo "<table>";
echo "<tr><td><b>".$_GET['q']."</b></td>";
echo "<td>".$sql."</td></tr>";
echo "</table>";
}
}
?>
---------------------------------------selectcustomer.js
var xmlHttp
function showCustomer(str)
{
var url="getcustomer.php?sid=" + Math.random() + "&q=" + str
xmlHttp=GetXmlHttpObject(stateChanged)
xmlHttp.open("GET", url , true)
xmlHttp.send(null)
}
function stateChanged()
{
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
{
document.getElementById("txtHint").innerHTML=xmlHttp.responseText
}
}
function GetXmlHttpObject(handler)
{
var objXmlHttp=null
if (navigator.userAgent.indexOf("Opera")>=0)
{
alert("This example doesn't work in Opera")
return
}
if (navigator.userAgent.indexOf("MSIE")>=0)
{
var strName="Msxml2.XMLHTTP"
if (navigator.appVersion.indexOf("MSIE 5.5")>=0)
{
strName="Microsoft.XMLHTTP"
}
try
{
objXmlHttp=new ActiveXObject(strName)
objXmlHttp.onreadystatechange=handler
return objXmlHttp
}
catch(e)
{
alert("Error. Scripting for ActiveX might be disabled")
return
}
}
if (navigator.userAgent.indexOf("Mozilla")>=0)
{
objXmlHttp=new XMLHttpRequest()
objXmlHttp.onload=handler
objXmlHttp.onerror=handler
return objXmlHttp
}
}
-------------------------------
il file .php deve avere solo l'output dei dati senza gli stili ecc......
e' un esempio di "ajax"

Scusate il mio post precedente, spero di averlo cancellato in tempo :P
dicevo esattamente quello che dice Gufo Rosso, secondo me e' la
soluzione ideale e snellisce tutto il lavoro che devono fare i client e
anche il server perche' non e' costretto a tirare su da db tutti i
comuni in un botto solo.
byez
Viandante

 una variabile di testo con tutta la tendinona di 8100 opzioni.
o_O
Meglio l'altra, manda giu' dal server beno byte possibile, per la gioia di
tutti
A dire il vero io avrei utilizzato i metodi "tradizionali" e nativi di JS
del tipo new Option()... pero' ho riscontrato pesantissimi rallentamenti...
cosa che non ho avuto nel primo caso o ancora meglio facendo degli
document.write()...

 document.write()...
Infatti. Per quello volevo fare un innerHTML che risulta (purtroppo) 
molto più veloce su IE che gestisce JS e DOM in maniera separata a 
quanto pare, contrariamente ai Gecko-based.
Document.write() non l'ho preso in considerazione, ma posso scrivere 
direttamente in un punto preciso della pagina?
Grazie
Marcello

 Funziona, ma con IE 6 ci mette piů di 60 secondi.

Dimenticavo:
la funzione la chiamo cosě:
var comuni=[
['123456','Comune1'],
['123457','Comune2'],
['123458','Comune3'],
]; // con tutti i comuni sono 8100 righe circa
carica_tendina(selectComuni,comuni,spanFeedTendina);
Ciao

 direttamente in un punto preciso della pagina?
Esatto!
tu ti puoi fare il tuo bel ciclo come ad es.:
<select>
<script type="text/javascript">
for( var i =0;i<10000;++i)
 document.write( '<option value="'+array_options[i][0] +'">' +
   array_options[i][1]+ '</option>' );
</script>
pero' questo va fatto al momento del caricamente della pagina, cioe'
diciamo che non la puoi cambiare dopo all'onload...
Se vuoi cambiare la select potresti fare un innerHTML che in effetti e'
piu' veloce delle new Option...

 piu' veloce delle new Option...
e io che avevo detto :( non mi considerate manco..... esosi :P