Newsgroup: it.comp.lang.javascript
Titolo: Oggetto XHR globale

Ciao a tutti,
mi sto domandando: ho dei vantaggi "prestazionali" a dichiarare solo una
volta un oggetto XHR globale e utilizarne il riferimento ogni qualvolta io
debba fare un richiesta al server, o no?
Una differenza che ci sarebbe nel dichiarlo globale, sarebbe l'impedimento
di richieste sovrapposte (in quato dovrebbe gestire e "mandare in
esecuzione" solo l'ultima), ci sono altri motivi? considerando che non
faccio richieste ogni 10 millisecondi bensģ nell'ordine del minuto?

 debba fare un richiesta al server, o no?
"E' una domanda a trucco"? (cit)
Te la rigiro: ci sono dei vantaggi "prestazionali" a dichiarare ogni
santa volta un nuovo oggetto XHR per ogni richiesta? (laddove, va da
se, non vi sono richieste connessioni in parallelo)
-- 
~ Io non soffro di pazzia, ne godo ogni minuto.
(I don't suffer from insanity, I enjoy every minute of it)

 se, non vi sono richieste connessioni in parallelo)
Provo a riformulare, vale la pena e/o c'è qualche motivo per cui istanziare
una volta sola e in maniera globale un oggetto XHR?
Perchè per "pulizia" di codice e se il browser non impiega 55 minuti a
farlo ogni volta, mi piacerebbe non utilizzare una variabile globale (nel
mio contesto)
Va da se che non ci sono richieste di connessioni in parallelo

 mio contesto)
Nessuno ti ha detto di usare una "variabile globale". E' da più di una
dozzina d'anni che sono noti approcci di sviluppo per evitarle. Ma qui
si sta parlando di un'altra cosa, concentrati sulla prima parte.
-- 
~ "Ho avuto la fortuna di unire mestiere e passione,
che secondo Stendhal equivale alla felicità."
(Roland Barthes)

 si sta parlando di un'altra cosa, concentrati sulla prima parte.
mah, a dire il vero, forse il punto o cmq quello che mi interessa è proprio
questo...
Hai tempo/voglia di illumonarmi un po'?

 Hai tempo/voglia di illumonarmi un po'?
Una parola sola: Singleton.
Ne abbiamo già discusso nel newsgroup altre volte. I Design Pattern
dovrebbero essere approcci ormai noti a chi sviluppa, almeno quelli
fondamentali.
-- 
~ "La fantasia è come la marmellata,
bisogna spalmarla su un solido pezzo di pane."
(Gore Vidal)

 fondamentali.
mi farò una cultura prima o poi...
cmq in questo caso come la vedi a dichiarare una variabile globale
all'interno della funzione ommettendo var, e controllare se è già definita
e in caso contrario istanziarla e poi riusare quella.
Ad es.:
function getXmlHttpRequest( )
{
   var xmlhttp = null;
   if( typeof window.XMLHttpRequest != "undefined" )
   {
      xmlhttp = new XMLHttpRequest( );
   }
   else if( typeof window.ActiveXObject != "undefined" )
   {
      /*@cc_on
      @if( @_win32 )
      {
         xmlhttp = new ActiveXObject( 'Microsoft.XMLHTTP' );
      }
      @end
      @*/
   }
   else if( typeof window.createRequest != "undefined" )
   {
      xmlhttp = window.createRequest( );
   }
   return xmlhttp;
}
function async_get_request( query, callback )
{
   if( typeof xmlhttp != "undefined" )
      xmlhttp = getXmlHttpRequest( );
   if( xmlhttp && query )
   {
      xmlhttp.open( "GET", 'index.php?s=' + ( new Date( ) ).getTime( ) +
Math.random( ) + '&' + query, true );
      xmlhttp.setRequestHeader( "If-Modified-Since", "Sat, 11 Jan 1977
00:00:00 GMT" );
      xmlhttp.onreadystatechange = function( evt )
      {
         if( xmlhttp.readyState == 4 )
         {
            if( xmlhttp.status == 200 )
               callback( xmlhttp.responseText );
            else
               alert( "Error; status = " + xmlhttp.status );
         }
      }
      xmlhttp.send( );
   }
}

    }
Lo usi l'ICEBrowser? Altrimenti, ricordati di non fornire mai supporto
per qualcosa che non conosci e non sei disposto a testare, esattamente
come faresti per IE, Firefox, Safari e via dicendo.
Sai benissimo che ogni browser spesso e volentieri si comporta in modi
differenti e su più fronti (CSS, JS, DOM, HTML), e se non conosci bene
la piattaforma rischi errori o risultati anomali.
Di regola, s'implementa codice che segue gli standard e le "eccezioni"
che desideriamo supportare e conosciamo (e di norma, questo si traduce
nel supportare IE per un banale discorso di base installate).
-- 
~ L'ingegnere non vive, funziona.

 nel supportare IE per un banale discorso di base installate).
In conclusione, servirebbe un qualcosa che attraverso la chiamata di una
funzioni restituisca il riferimento di un oggetto di cui riesce a tenerne
copia da dopo la prima chiamata
Immagino che sia un qualche modo con le chiusure, ma come si possa fare
senza mai dichiarare una cavolo di variabile boh...
Sarebbe bello/interessante che mi potessi fare un'esempio
ciao e grazie

 Sarebbe bello/interessante che mi potessi fare un'esempio
Google it's your friend:
http://www.google.it/search?q=singleton+javascript
-- 
~ La realtà è un'illusione causata dall'assenza di alcool.

 
http://www.google.it/search?q=singleton+javascript
bene tra i miei mille casini sono andato a spulciare qualche link...
e sono subito rimasto folgorato facendo scoperte nuove,
ok, io ho trovato questo:
http://html.it/guide/esempi/oop/singleton_javascript.html
dal quale ho fatto la scoperta incredibile che all'interno di una funzione
si possono richiamare le variabili nel proprio interno usando il
riferimento della funzione stessa, io pensavo si potesse fare solo con
this, ho capito che in questo modo si è un po' simulato il concetto di
variabile privata e pubblica.
Al chè ho voluto subito fare un mio singleton (di cui ne esisteranno 10000)
un po' più generico di quello dell'esempio del link, e questo è quello che
ho prodotto:
function Singleton( objectName )
{
    if( typeof Singleton[objectName] == 'undefined' )
       eval( "Singleton['"+objectName+"'] = "+objectName+"( );" );
    return Singleton[objectName];
}
però non mi fa impazzire perchè ho usato eval, ma mi sembra che funzioni e
che sia generico, però l'utilizzo che ne ho subito fatto temo che non sia
molto orientato agli oggetti:
praticamente nella funzione di qualche post fa io non faccio altro che
dichiarare una variabile locale che prende il riferimento:
function async_get_request( query, callback )
{
   var xmlhttp = Singleton( 'getXmlHttpRequest' );
   if( xmlhttp && query )
   {
      xmlhttp.open( "GET", query, true );
      xmlhttp.setRequestHeader( "If-Modified-Since",
         "Sat, 11 Jan 1977 00:00:00 GMT" );
      xmlhttp.onreadystatechange = function( evt )
      {
         if( xmlhttp.readyState == 4 )
         {
            if( xmlhttp.status == 200 )
               callback( xmlhttp.responseText );
            else
               alert( "Error; status = " + xmlhttp.status );
         }
      }
      xmlhttp.send( );
   }
}
A proposito, io pensavo felicemente che una funzione così, potesse andare
bene, ma mi sono accorto che FF si incaxxa di brutto se cerco di fare più
richieste ravvicinate , cioè se l'ultima richiesta non è conclusa, mi va in
errore a differenza di IE che ignora la precedente e cosidera solo l'ultima
(comportamento che pensavo avrebbe avuto anche FF)
come posso fare?

 come posso fare?
Gestire l'interruzione di richieste in corso, cosa che al momento non
fai.
Se cerchi su google o nel NG, dovresti trovare informazioni in merito
alla questione.
-- 
~ "La realtà è ciò che, quando smetti di crederle, non va via."
(Philip K. Dick)

 Anzi non è coretto, forse è meglio dire: statica e privata...
Se parliamo di "simulazione", direi che con tale approccio simuli
quelle che sono chiamate "proprietà di classe" (o anche statiche,
è vero, ma assolutamente non private).
Un metodo/proprietà statica o di classe, non viene trasmesso alle
istanze della classe ed è indipendente da queste.
In Javascript, un esempio è dato dal metodo "fromCharCode".
-- 
~ Io ho una filosofia semplice:
Riempi ciò che è vuoto. Vuota ciò che è pieno. Gratta ciò che prude.
(A. R. Longworth)

 fai.
Mmmm, mi dai un'idea?

 Mmmm, mi dai un'idea?
Cercare su Google ti dovrebbe già fornire parecchie informazioni,
ma anche un *minimo* di debugging sul tuo codice, ti dovrebbe già
chiarire cos'è che va in errore e perché, e quindi come evitarlo.
Verifica la riga che Firefox ti segnala. Metti un alert. Almeno i
fondamentali, vedi di farli. :) Se nonostante questo ti sfugge il
nocciolo della questione ne riparliamo. Gli approcci in tal senso
possono essere diversi.
E ne avevamo già discusso in questo NG, ripeto, almeno una volta.
-- 
~ "E' bello essere vivi.
Ci sono tante cose che non si possono fare da morti."

 E ne avevamo già discusso in questo NG, ripeto, almeno una volta.
mi sono salvato un link che forse potrebbe essere la volta di cui parli,
appena posso domani ci darò un'occhiata
Ciao e grazie

 Ciao e grazie
De nada.
-- 
~ "Ciò che il cuore conosce oggi, la testa comprenderà domani"
(Seneca)

 Se l'hai fatto, dove sono i risultati?
allora i risultati sono i seguenti, in effetti dopo uno studio un po' più
approfondito della cosa e dopo avergli messo alert avvunque (evitiamo
volgarità :)
Chissa' quante cose mi correggerai :|
per FF gli stati intermedi allo 0 (uninitialized) e al 4 (complete) sono
sacri, cioè tentativi di leggere lo status, rispedire header di un nuovo
messaggio e/o sperirlo proprio, lo fanno andare in errore perchè non viene
invocato un abort del messaggio come invece sembra che accada con ie in
automatico...
ma il bello deve ancora venire, se si lancia l'abort() l'oggetto va in
readyState = 4 (il chè potrebbe avere anche senso) pero' sollevando
un'eccezione meravigliosa rispetto al readyState = 4 di quando viene
terminata "normalmente", infatti la proprietà status in questo caso non è
accessibile similmente agli stati intermedi di cui si parlava prima
in conclusione bisogna gestire quest'eccezione evitando di trattare
readyState = 4 come si farebbe nei casi di no-abort().
E il bello non è ancora arrivato, mi sembra di aver capito che FF, finchè
non invia quel readyState = 4 a seguito dell'abort() non permette l'invio
di un nuovo msg analogamente ai casi precedenti, quindi se si vuole
sovraporre una nuova richiesta ignorando la precedente, credo che
bisognerebbe agire direttamente all'interno dell'onreadystatechange che in
teoria si potrebbe cambiare prima di evocare l'abort
Insomma che ci ho perso la mattina e forse mi sono un po' più chiarito
l'idee, pero' non sono riuscito a fare niente di meglio di quello fatto
inconsapevolmante ieri e cioè: anullare l'onreadystatechange evocare
l'abort e utilizzare una nuova istanza dell'oggetto XHR permettendo al
precedente di impegare quei millesimi di secondi a terminare e/o a fare
quello che vuole...
Non nascondo che arrivato a questo punto mi piacerebbe riuscire ad evitare
il riistanziamento che sono sicuro essere evitabile, ma avrei bisogno di
una dritta, perchè sono altrettanto sicuro che mi sono perso qualcosa...
ciao
aspetto le tue correzioni :)
fiducioso che tu mi dia anche 2 righe di codice :P

 fiducioso che tu mi dia anche 2 righe di codice :P
Codice per cosa? Qui il problema è di conoscenza e  di logica, non vi
è alcun codice da scrivere, c'è solo da capire.
-- 
~ "Io ho fatto questo, dice la mia memoria
Io non posso aver fatto questo, dice il mio orgoglio.
Alla fine, è la memoria ad arrendersi." (Nietzsche)

 approfondito, se la mia memoria non m'inganna.
Se non ricordo male, ne parlammo anche tu ed io all'epoca della mia chat,
ricordi? Il punto è, se non erro, che in caso di terminazione forzata della
richiesta xhr firefox passa direttamente allo stato 4 senza passare per gli
stati intermedi (ad esempio, direttamente da 2 a 4) e non è possibile
accedere alla proprietà status. La cosa ha senso, del resto, giacché non ha
senso parlare di "status" (ovverosia, in sostanza, dello stato della
*risposta* ottenuta) quando la richiesta stessa è stata abortita e dunque
risposta non v'è; è altresì ragionevole che il readystate valga 4, poiché
in effetti lo stato della *richiesta* è "completato".
Mi pare :)
-- 
Nando [?]
Apostolo della Prova

 Il punto è, (..) Mi pare :)
Questo lo so io, lo sai tu, e se lui ci fosse arrivato allo stesso modo
in cui l'hai fatto te (anche aiutandosi tramite google ed il precedente
thread, ma traendo da solo le sue conclusioni) sarebbe stato meglio. :)
Soprattutto viste le successive lacune che ho notato su dei passaggi.
Ormai dovresti saperlo bene quanto me, che ciò che maggiormente conta è
"come" si raggiunge una certa conoscenza, e non la conoscenza in sé. :)
-- 
"Se c'è qualcosa di più importante del mio ego su questa nave,
la voglio catturata e fucilata."

 "come" si raggiunge una certa conoscenza, e non la conoscenza in sé. :)
Sono sempre stato irruente e frettoloso :-S


 è alcun codice da scrivere, c'è solo da capire.
sperando di avere fatto qualche passo in avanti (altrimenti mi sparo -
visto il tempo che mi sta facendo perdere questa cosa), mi potresti
spiegare il perchè del fallimento della seconda richiesta:
var xmlhttp = new XmlHttpRequest( );
xmlhttp.open( "GET", '...', true );
xmlhttp.setRequestHeader( ... );
xmlhttp.send( null );
xmlhttp.abort( );
xmlhttp.open( "GET", '...', true );
xmlhttp.onerror = function (e)
{
  try
  {
     alert(  e.target.readyState )
     alert(  e.target.status )
  }
  catch( e )
  {
     alert(e);
  }
}
xmlhttp.setRequestHeader( "..." );
xmlhttp.send( null );
Evocando l'abort della prima richiesta, mi sono accorto che l'ogetto cambia
il readyState a 4 e quindi viene evocato l'onreadystatechange (che per
semplicita non ho gestito), perchè cmq l'operazione è completata (e mi sta
bene, sono d'accordo, l'abbiamo già detto :)
Quello che non capisco è perchè mi fallisce quella immediatamente
sucessiva, come se l'oggetto fosse ancora in una fase di interruzione delle
richieste, come se facessi troppo veloce e lui non avesse ancora finito con
la precedente...
A questo punto allora ho provato a lancira la seconda richiesta solo dopo
che viene evocato l'onreadystatechange della prima e in questo caso mi
sembra che vada a buon fine - questo sembrerebbe avalorizzare le mie
ipotesi ma io rischio e mi gioco il gioielli di famiglia e scometto che
sono ancora in alto mare :(
in fine alto mare per alto mare, ho tentato di lanciare la seconda
richiesta ritardandola con un setTimeout e anche in questo caso sembrerebbe
andare a buon fine (anche con 0ms - è bastato decontestualizzarla),
premesso che questa non la ritengo una soluzione, mi piacerebbe capire
meglio che cosa succede, io mi sono arenato e oltre non rieso ad andare :(
Pensaci tu, please :)

 spiegare il perchč del fallimento della seconda richiesta:
Questo č un problema di tutt'altra natura, difatti non ottieni alcun
errore (a meno che tu non vada a chiedere lo status, appunto, quando
non ne hai).
In IE quando invochi il metodo "open" viene reinizializzato tutto, č
questo il motivo (che spero tu sappia) del perché gli eventi vengono
impostati DOPO l'open, e ogni volta che viene chiamato.
Su Firefox no, l'onreadystate potresti anche impostarlo prima e solo
una volta.
Se lo imposti prima dell'open della prima richiesta, noterai come la
funzione venga chiamata anche per i metodi "open", per esempio.
Il punto č che essendo un oggetto cosě condiviso e facendo richieste
asincrone, non dai il tempo all'engine di reimpostare le risorse. In
IE il problema non si pone perché viene eliminato a monte.
Nel thread di Nando comunque, si parla anche di problemi come questi
e di come discriminare le chiamate avvenute con successo; sebbene il
contesto fosse un poco diverso (cambio pagina e onunload mi pare, ma
se hai letto recentemente tutto il thread te lo ricorderai meglio di
me, ma il comportamento č il medesimo).
Con un approccio OOP riesci a risolvere elegantemente il tutto.
-- 
~ "Gesů ha avuto la sfortuna che su quello che ha detto ci hanno
costruito sopra una religione."
(Josč Saramago)

 Con un approccio OOP riesci a risolvere elegantemente il tutto.
dai vedro' cosa riesco a fare...

 dai vedro' cosa riesco a fare...
Bravo... Se questo thread fosse anche solo riuscito a spronarti a uno
sviluppo più OOP, avrebbe già fatto tanto. :)
-- 
~ Plagiarism is copying from one source;
research is copying from two or more
(Wilson Mizner)

 sviluppo più OOP, avrebbe già fatto tanto. :)
Ma sì, un po' l'ha fatto :)
Ora ti farò un breve resoconto delle mie evoluzioni:
ho creato un oggetto che vuole in qualche modo "estendere" l'oggetto
XMLHttpRequest, cercando di introdurre una sorta di gestione degli errori e
dell'abort alla IE e semplificando un po' le procedure di richiesta delle
pagine.
L'idea è che si istanzi uno solo di questo oggetto (introducendo un domani
anche il concetto di Singleton) al momento attraverso una variabile
globale.
Ho preso spunto dai tanto citati post e ho implementato la cosa cercando di
rendere sicuro l'accesso allo status della risposta tenedo memoria degli
readyState che si susseguono e considerando buono solo quello che vale 4 la
cui versione salvata invece valga 3, e inoltre ho introdotto il concetto di
coda ad un solo elemento che è ottima per eliminare subito eventuali
richieste pendenti a causa di lentezze del server e utile se non necessaria
per l'autorichiesta a seguito di un abort dovuto alla sovrapposizione di
una richiesta pendente (boh chissa cosa ho detto), ed credo che sia
fondamentale se si vuole attendere che il browser concluda le eventuali
operazioni dopo la ricezione della pagina...
Comunque ti posto un po' quello che ho realizzato, non considerare per il
momento tutte le chiusure che ho introdotto, poi metteremo a posto anche
quelle e nemmeno altre ottimizzazioni secondarie che si possono fare,
quello che mi interessa sono gli errori concettuali che sto facendo...
perchè non ho avuto modo di indagare ma con IE riscontro un problema al
tentativo di richiesta multipla, ho preferito inviare il codice così com'è
in modo che domani lo potessi vedere...
function myXmlHttpRequest( )
{
   this.xmlhttp = getXmlHttpRequest( );
   this.lastReadyState = 0;
   this.req = null;
}
myXmlHttpRequest.prototype.onReadyStateChange =
function( callbackOnSuccess, callbackOnError )
{
   var self = this;
   return function( evt )
   {
      if( self.xmlhttp.readyState == 4 )
      {
         if( self.lastReadyState == 3 )
         {
            if( self.xmlhttp.status == 200 )
            {
               if( typeof callbackOnSuccess == 'function' )
               {
                  self.executingCallback = true;
                  callbackOnSuccess( self.xmlhttp.responseText );
                  self.executingCallback = false;
               }
            }
            else
            {
               alert( "Unexpected status: " + self.xmlhttp.status );
               if( typeof callbackOnError == 'function' )
               {
                  self.executingCallback = true;
                  callbackOnError( );
                  self.executingCallback = false;
               }
            }
         }
         else
         {
//            alert( "Unexpected lastReadyState on ReadyState = 4: " +
                self.lastReadyState );
            if( typeof callbackOnError == 'function' )
            {
               self.executingCallback = true;
               callbackOnError( );
               self.executingCallback = false;
            }
         }
         self.lastReadyState = 0;
         if( self.req )
         {
            var req = self.req;
            self.req = null;
            self.request( req );
         }
      }
      else
      {
         self.lastReadyState = self.xmlhttp.readyState;
      }
   }
}
myXmlHttpRequest.prototype.request = function( req )
{
   if( ! req )
      return;
   switch( req.type )
   {
      case 'async_get':
      {
         this.xmlhttp.open( "GET", 'index.php?s=' +
           ( new Date( ) ).getTime( ) + Math.random( ) + '&' +
           req.query, true );
         break;
      }
      case 'async_post':
      {
         this.xmlhttp.open( "POST", 'index.php?s=' +
           ( new Date( ) ).getTime( ) + Math.random( ) + '&' +
           req.query, true );
         break;
      }
   }
   this.xmlhttp.setRequestHeader( "If-Modified-Since",
   "Sat, 11 Jan 1977 00:00:00 GMT" );
   if( ! req.type.indexOf( 'async' ) )
      this.xmlhttp.onreadystatechange =
          this.onReadyStateChange( req.callbackOnSuccess,
             req.callbackOnError );
   this.xmlhttp.send( null );
}
myXmlHttpRequest.prototype.getRequest = function( type, query,
callbackOnSuccess, callbackOnError )
{
   var req = { 'type' : type, 'query' : query,
     'callbackOnSuccess' : callbackOnSuccess,
     'callbackOnError' : callbackOnError };
   if( this.lastReadyState == 0 )
   {
      this.request( req );
   }
   else
   {
      this.req = req;
      if( ! this.executingCallback )
         this.xmlhttp.abort( );
   }
}
usata cad es. così:
var http = new myXmlHttpRequest( );
function fun( )
{
   http.getRequest( 'async_get', 'page=test_sleep',
     function(txt){alert(txt);} );
}
<a href="#" onclick="fun();return false">req</a>

 ho preferito inviare il codice cosě com'č
cut 
Non mi parli piů :( 

 Non mi parli più :(
Sinceramente non mi sembrava che il post in sé necessitasse di una
risposta; non mi pare che vi siano domande o altro. Inoltre, tutto
ciò che doveva esser detto sull'argomento è già stato fatto, qui o
nell'altro thread. Il resto sta a te.
Un piccolo appunto: non usare "self" come nome di variabile, viene
già usato dal browser come sinonimo di window.
-- 
~ Se cerchi una mano disposta ad aiutarti,
la trovi alla fine del tuo braccio.