Visualizzazione post con etichetta function. Mostra tutti i post
Visualizzazione post con etichetta function. Mostra tutti i post

martedì, novembre 25, 2014

Programmazione asincrona e callbacks

Una analogia per capire la differenza tra programmazione sincrona e asincrona.
Normalmente gli uomini si comportano in maniera sincrona, le donne in modo asincrono :))
Quando faccio il caffè al mattino, aspetto quei 4 secondi davanti alla tazzina che si riempie.
Mia moglie, durante quei 4 secondi magari comincia a svuotare la lavastoviglie.

In java, normalmente, l'esecuzione delle istruzioni avviene in maniera sincrona, una istruzione viene eseguita non prima che la precedente abbia finito; se si vuole una sorta di parallelismo, bisogna usare i threads, con tutto il sovracarico (overhead), in termini di risorse, che ne consegue.

In javascript non esistono i threads. Tutte le nostre istruzioni vengono eseguite, sempre, in un unico thread ma esiste la possibilità di eseguire le istruzione in modalità asincrona.

Consideriamo lo scenario in cui dobbiamo effettuare una richiesta ad un server.

In modalità sincrona avremmo ad esempio

 richiesta = preparaRichiesta();  
 risposta = mandaRichiestaSincrona(richiesta);  
 visualizza(risposta);  

Se il server impiega 10 secondi a rispondere, il nostro codice è bloccato alla seconda istruzione, non si possono eseguire altre istruzioni nel frattempo.

In modalità asincrona avremmo invece, grazie alla possibilità di passare una funzione come parametro

 richiesta = preparaRichiesta();  
 mandaRichiestaAsincrona(richiesta, function(risposta) {  
   visualizza(risposta);  
 });  
 visualizza("Siamo in attesa di risposta dal server ...");  

In questo caso, la seconda istruzione è asincrona, dopo la sua esecuzione, il nostro programma continua con l'istruzione successiva: quando il server risponderà, con i suoi tempi, verrà eseguita la funzione di callback passata come argomento alla funzione asincrona.

Tecnicamente, il supporto alla programmazione asincrona è implementato, nell'interprete javascript, tramite l'utilizzo di

  • una coda di messaggi
  • un ciclo principale di gestione eventi
Tutte le istruzioni che devono essere eseguite dal nostro programma vengono inserite in una coda di messaggi che viene gestita da un ciclo principale che svuota ed esegue, in un unico thread, le istruzioni presenti nella coda.

Nel caso di una funzionalità asincrona, dipendente da un evento esterno al nostro programma, un componente del runtime di javascript aggiunge alla coda dei messaggi la funzione di callback da eseguire, con i relativi parametri, non appena l'evento si è verificato.

Le funzioni di callback non sono mai interrompibili, così come qualsiasi funzione in javascript: in questo modo non esite mai un problema di accesso ad aree di memorie condivise da thread diversi, visto che il ciclo principale viene eseguito in un unico thread.

Avrete già sentito l'acronimo AJAX: Asynchronous Javascript And Xml: è una tecnica che permette di effettuare richieste http ad un server in modalità asincrona, sfruttando il meccanismo visto sopra: quando il server risponde, viene eseguita la funzione di callback registrata con la richiesta, che, tipicamente, modifica il DOM (Document Object Model) della pagina html corrente.

Il DOM non è altro che la rappresentazione, ad albero, in memoria, del documento html.


Una sua modifica potrebbe essere, ad esempio, la creazione di una tabella con i dati restituiti dal server.

L'utente, mentre il server risponde, ha ancora la possibilità di interagire con la pagina corrente, generando eventi che possono essere gestiti dal ciclo principale in attesa della risposta del server.

E l'XML che c'entra? Storicamente era il formato scelto per rappresentare i dati scambiati tra client e server. Ora si preferisce il formato JSON e provate ad indovinare un pò il perche ...

Più in la, vedremo come implementare richieste asincrone a componenti lato server, componenti ovviamente implementati in javascript grazie alla piattaforma nodejs ;)

Alla prox.
Ivan

















domenica, novembre 16, 2014

Scope delle variabili e non intendo le ramazze

Non amo i neologismi esteri, quando posso preferisco usare la nostra bella lingua, ma come si fa a tradurre il termini scope?

Non sono le ramazze, ma ogni buon informatico ne capisce il significato: lo scope di una variabile definisce l'ambito di validità della variabile stessa.

In java lo scope è definito da un qualsiasi blocco di istruzioni delimitato dalla coppia di parentesi graffe.

In javascript lo scope è, o globale, o definito a livello di funzione.

Le variabili globali sono nuove proprietà dell'oggetto window e sono accessibili da qualsiasi funzione definita a qualunque livello.

Le varibili definite a livello di funzione, sono locali alla funzione stessa e non sono accessibili da altre funzioni, se non dalle funzioni interne per creare il meccanismo di closure visto nel
post precedente.

In javascript non esiste  il concetto di scope di blocco, anche se dichiariamo una variabile all'interno di un blocco delimitato dalle parentesi graffe, è come se spostassimo la dichiarazione all'inizio della prima funzione in cui la variabile è dichiarata:

 var global = 5;  
   
 var miaFunzione = function() {  
        
      b = 100;  
   
      if (global == 5) {  
             
           var local = 10;  
        
      }  
        
      console.log(local);       
 };  
 
 miaFunzione();  
 console.log(b);  

global è una variabile globale, puo' essere acceduta da miaFunzione.

La variabile b è dichiarata senza la parola chiave var, purtroppo lo si puo' fare con lo sgradevole effetto di rendere b globale, è ovviamente sconsigliato di scrivere codice del genere.

Local, nonostante dichiarata a livello del blocco if, subito dopo la dichiarazione è come se fosse spostata all'inizio della funzione: l'istruzione di scrittura sulla console fuori dal blocco stampa il valore 10, tale meccanismo si chiama hoisting.

L'ultima istruzione stampa il valore 100, la variabile b è in effetti, una variabile globale solo perchè non si è utilizzata la parola chiave var: usatela!

Ok, adesso sappiamo tutto sulle scope, usatele bene :))
Alla prox.
Ivan



sabato, novembre 15, 2014

Spaghetti o Ravioli?

Siamo ora pronti a comprendere il codice presentato nel primo post, lo riscrivo qui per comodità

  var modulo = (function() {  
                   var f1 = function() {  
               
                            },  
                       f2 = function() {  
                 
                            },  
                       f3 = function() {  
                 
                            };  
               
                       return {  
                         f1 : f1,  
                         f2 : f2,
                         f3 : f3
                       };   
                })();  
   

Cosa contiene la variabile modulo? Contiene il risultato della esecuzione immediata della funzione dichiarata a destra, tale funzione ritorna il seguente oggetto


 {  
   f1 : function() {},  
   f2 : function() {}  
 }  
   
   

e quindi window.modulo espone le uniche proprietà f1 e f2 che in questo caso sono funzioni.

Le inner function, cioe le funzioni dichiarate all'interno di un'altra funzione, hanno l'importante proprietà di poter accedere alle variabili locali e i parametri dell'outer function anche quando l'outer function ha terminato la sua esecuzione.

Questa caratteristica, chiamata closure, insieme al concetto di  IIFE: Immediate Invocation Function Expression,  acronimo pomposo per descrivere una funzione che viene invocata appena subito dopo la sua dichiarazione, permette di creare degli oggetti che espongono solo le funzioni che vogliamo, nascondendo i dettagli implementativi; ciò ci permette di modularizzare il nostro codice, passando da un codice a spaghetti a un codice a ravioli :)

Facciamo ancora un esempio:

 var biblioteca = (function(nome) {  
        
      var libri = [],  
       
           nomeBiblioteca = nome,  
          
           inserisciLibro = function(libro) {  
               libri.push(libro);  
           },  
          
           getNomeBiblioteca = function() {  
               return nomeBiblioteca;  
           },  
          
           numeroLibri = function() {  
               return libri.length;  
           };  
   
          return {  
            insert : inserisciLibro,  
            getName : getNomeBiblioteca,  
            length : numeroLibri  
          };  
   
 })('civica di milano');  


 biblioteca.insert({titolo:'guerra e pace'});
 console.log(biblioteca.getName());
 console.log(biblioteca.length());

biblioteca è un oggetto, ritornato dalla funzione che viene immediatamente eseguita, espone dunque solo i tre metodi insert, getName, e length.

La variabile locale libri non è accessibile dall'esterno, essendo una variabile locale di una funzione,

I metodi dell'oggetto ritornato, possono ancora accedere alle variabili locali della funzione esterna, anche se la funzione esterna ha già finito la sua esecuzione: notate bene che in questo caso la eseguiamo immediatamente passandole il parametro 'civica di milano'.

Le linee di codice successive, memorizzano il libro dal titolo 'guerra e pace' nell'array libri, che esiste ancora nonostante la funzione precedente ha finito la sua esecuzione, stampano sulla console rispetivamente 'civica di milano' e 1.

Spero che ora non abbiate più dubbi sul potente concetto di closure, che ci permette di definire oggetti complessi nascondendo la loro complessita a chi deve utilizzarli.

Cominciate a utilizzare le IIFE e il vostro codice passerà da un groviglio di spaghetti a dei ravioli gustabili  uno ad uno :).

Alla prox.
Ivan

venerdì, novembre 14, 2014

Json e dintorni

Prima di affrontare il concetto chiave di closure, vediamo dunque di definire correttamente quello di oggetto in javascript.

Javascript non è tipizzato, le variabili dichiarate con la parola chiave var possono contenere numeri,stringhe,booleani (true o false), null e undefined.
I numeri, le stringhe e i booleani sono a tutti gli effetti degli oggetti, visto che hanno anche loro dei metodi, anche se sono oggetti immutabili.

Un oggetto è un contenitore di proprietà, dove  le proprietà, separate dalla virgola, hanno un nome ed un valore.
Una proprietà puo essere rappresentata da qualsiasi stringa, compresa la stringa vuota.
Il valore di una proprietà può essere un qualsiasi valore eccetto undefined

Gli oggetti sono utili per contenere e organizzare i dati, gli oggetti possono contenere altri oggetti e così possono rappresentare facilmente strutture ad albero o graphi.

Il modo standard di rappresentare gli oggetti in javascript è costituito dalle parentesi graffe aperte e chiuse che circondano zero o più coppie nome/valore.

 var oggetto_vuoto = {};  
   
 var dipendente = {  
   nome: "ivan",  
   cognome:"saracino"  
 };  
   
 var volo = {  
   compagnia: "alitalia",  
   numero: 345,  
   partenza: {  
    citta: "roma",  
    orario: "14/11/2014 13:30"  
   },  
   arrivo: {  
    citta: "milano",  
    orario: "14/11/2014 15:00"     
   }  
 };  

Ultimamente si usa il formato JSON (Javascript Standard Object Notation) per lo scambio dati tra compenenti distribuiti: il formato JSON nasce proprio dal linguaggio Javascript.

Per recuperare un valore da una proprietà di un oggetto

   
 // metodo standand di navigazione oggetti  
 volo.partenza.citta // roma  
   
 // metodo alternativo che mette in luce la natura di collezione associativa 
 // di coppie nome/valore  
 dipendente["nome"] // ivan  
   
 //proprieta noon presenti su oggetto  
 dipendente.nonesisto // undefuned  
   
 //tentativo di accedere a proprietà di proprietà inesistenti  
 dipendente.nonesisto.proprieta // eccezione a run time  

Per scrivere le proprietà di un oggetto

 // aggiornamento di una proprietà esistente  
 dipendente.nome = "ciccio";  
   
 // se una proprietà non esiste, viene creata  
 // dinamicamente!  
 dipendente.età = 43  

Le variabili che contengono gli oggetti sono dei puntatori agli oggetti in memoria.

Quando passiamo un oggetto come parametro, il passaggio del parametro è per copia  ( qui sono in disaccordo col buon Douglas Crockford che dice che il passaggio è by reference) come dimostrato dal seguente frammento di codice:

 var x = {p : 1};  
   
 var y = x;  
   
 y.p = 2;  
   
 x.p vale 2, stiamo modificando lo stesso oggetto   
 tramite lo stesso puntatore  
   
   
 definiamo una funzione che modifica la proprietà  
 di un parametro  
   
 var f = function(par) {par.p = 3};  
   
 invochiamo la funzione passando l'oggetto x  
   
 f(x);  
   
 x.p vale 3, nella funzione usiamo la copia   
 del puntatore x per modificare lo stesso oggetto in memoria  
   
 cerchiamo di cambiare l'oggetto puntato da par  
   
 var f = function(par) {par = {p:4}};  
   
 invochiamo nuovamente la funzione passando l'oggetto x  
   
 f(x);  
   
 x.p vale ancora 3, par è una copia del puntatore x,   
 copia che muore quando finisce la funzione f,  
 x punta all'oggetto originale  

In effetti il passaggio dei parametri è identico al linguaggio Java.

Ci sono altre considerazioni da fare sugli oggetti, ma credo sia opportuno dedicarci un post apposito.

Alla prox.
Ivan

E finalmente trovai gli oggetti

Nel primo post abbiamo visto come creare un modulo javascript rappresentato dalla variabile globale modulo che altro non è che un oggetto che espone le funzioni f1, f1, f3.

Qual è il vantaggio?

Invece di avere 3,4,5, ...N oggetti globali ne abbiamo uno solo e non si rischia, col tempo, di avere collisioni tra i nomi delle funzioni  (succede più spesso di quanto non si creda) generando errori difficili da risolvere.

Se avete letto con attenzione, dovrebbe risultare chiaro che, in javascript, le funzioni sono oggetti: possono essere memorizzate in varibile e possono essere passate come argomenti di altri funzioni.

Quando il browser carica una pagina html e incontra un nodo <script></script>, esegue immediatamente il codice presente in esso, il contesto di esecuzione dell'interprete javascript presenta un oggetto globale window  a cui vengono aggiunte dinamicamente le varie variabili definite nel nostro codice.

Riprendendo l'esempio del  primo post , l'oggetto window, dopo l'esecuzione della prima versione dell'esempio, presenta le nuove proprietà f1, f2,f3 il cui valori sono oggetti di tipo funzione.

Per provare l'affermazione precedente basta aprire una console javascript (F12 su qualsiasi browser moderno) e digitare window.f1, window.f2 o window.f3: la console mostrerà il valore delle tre proprietà f1,f2,f3 di window

Ecco il risultato prodotto dalla console:


Ovviamente per eseguire le funzioni, scriveremmo window.f1(); window.f2(); o window.f3(); oppure f1(); f2(); o f3() oppure this.f1(); this.f2(); this.f3(); il che significa che this = window nel contesto globale di esecuzione.

Nel secondo esempio,invece, verrà creata una unica proprietà window.modulo che questa volta è un oggetto che espone le tre funzioni per eseguire le quali scriveremo window.modulo.f1(); window.modulo.f2(); o window.modulo.f3();

Non ci stupirà allora che:

 var f1 = function() {  
                alert('f1');  
      };  
   
 Equivalente in tutto e per tutto a   
   
 function f1() {  
      alert('f1');  
 }  

La prima dichiarazione mette in risalto il concetto che le funzioni sono oggetti.

Avevo gli oggetti che cercavo sotto gli occhi e non lo sapevo :))

Alla prox.
Ivan