Iniziamo ad utilizzare le funzioni Javascript

In questa lezione vedremo come sfruttare alcune API JavaScript di nostra conoscenza nel codice Node.js attraverso degli esempi molto semplici.

Node.js è un framework leggero realizzato sopra il motore JavaScript V8 di Google. I punti di forza del framework sono l’utilizzo della sintassi JavaScript, in modo da risultare immediato a chi sviluppa codice orientato al Web, unita alla possibilità di creare script server-side grazie alla potenza del compilatore V8. Abbiamo già illustrato le potenzialità di Node.js, spiegandone l’architettura e principi di funzionamento nella prima lezione (vedi qui).

In questa lezione vedremo come sfruttare alcune API JavaScript di nostra conoscenza nel codice Node.js. Se guardiamo infatti all’esempio della prima lezione, potremmo non essere del tutto convinti della somiglianza tra Node.js e JavaScript. Per chiarire questo punto vedremo degli esempi molto semplici, basati su implementazioni alternative dello script “Hello World!” della prima lezione. Dopo aver chiarito questo aspetto inizieremo ad approfondire l’argomento, discutendo le caratteristiche architetturali di Node.js che riguardano la comunicazione sopra il protocollo HTTP.

Iniziamo quindi con nell’inserire alcune funzioni JavaScript nel server che abbiamo introdotto nella prima lezione. Per comodità riportiamo qui sotto il codice del nostro “serverino”, leggermente modificato per adattarsi meglio al contenuto di questa lezione

 

 

prima di iniziare ad apportare modifiche al codice, chiariamo alcuni aspetti dell’architettura. Pur trattandosi di codice scritto in stile JavaScript, dobbiamo ricordarci che stiamo eseguendo uno script lato server. In particolare ciò significa che ogni modifica allo script non sarà visibile semplicemente eseguendo un refresh del browser, ma dovremo riavviare il nostro server per renderle effettive. Se stiamo lavorando a riga di comando ciò significa interrompere lo script precedente e rilanciare nuovamente il server, ad esempio

 

 

Chiarito questo aspetto siamo pronti a modificare il codice inserendo alcune funzioni JavaScript. Per comodità sceglieremo due funzioni molto popolari, che ben si prestano allo scopo: setTimeout e setInterval.

setTimeout e setInterval

La nuova versione del server sarà la seguente

 

Vediamo quali sono le novità: all’inizio creiamo il server come nel caso precedente. Gli unici cambiamenti si trovano perciò all’interno della funzione onRequest. Qui abbiamo inserito le due funzioni JavaScript setTimeout e setInterval. Assumendo di rivolgerci a chi già conosce JavaScript non entriamo nel dettaglio di queste funzioni, limitandoci a ricordare che la prima (setTimeout) specifica una funzione callback da eseguirsi dopo un certo ritardo, che nel nostro caso è pari a 5000 ms (5 secondi). La seconda (setInterval) invece permette di ripetere in modo ciclico lo stesso codice, nel nostro caso ogni 1000 ms (1 secondo). Ciò significa che il blocco

 

 

verrà ripetuto ad oltranza ogni secondo.

Il risultato sarà il seguente: alla prima richiesta inviata al server (ad esempio via browser all’indirizzo http://localhost:8080) entreremo nella funzione onRequest, eseguendo tutto il codice contenuto al suo interno. Per effetto dell’architettura asincrona di Node.js (ispirata da JavaScript) le due funzioni setTimeout e setInterval verranno eseguite subito, mentre le callback “al loro interno” verranno eseguite nei tempi dichiarati come argomento. Otterremo quindi la scrittura per cinque volte del testo “Hello World”, come specificato dalla setInterval, e solo dopo chiuderemo la trasmissione dei contenuti come indicato dalla funzione setTimeout.

L’esempio permette di chiarire il comportamento di Node.js. Innanzitutto notiamo che in questo caso l’ordine con il quale compaiono le due funzioni setTimeout e setInterval è ininfluente ai fini del risultato: ciò è dovuto al comportamento asincrono del framework, per cui l’ordine di esecuzione viene definito dai parametri temporali (5 secondi e 1 secondo). In secondo luogo osserviamo che il risultato non si comporta come il normale HTML. Ciò è dovuto al fatto che abbiamo inviato al browser una risposta “grezza”, senza specificare alcun markup. Per questo motivo il browser probabilmente visualizzerà il risultato usando il quirks mode.

Headers HTTP

Se facciamo girare il server proposto a pagina precedente, probabilmente non vedremo nulla per i primi cinque secondi, e solo alla fine apparirà il contenuto completo. Ciò è corretto, perché solamente dopo cinque secondi eseguiamo l’istruzione response.end() che termina la trasmissione della risposta. Se però guardiamo alla consolle del server vedremo che continua a comparire il messaggio di log “I’m writing”. Anche questo è corretto perché la funzione response.write() continuerà ad essere eseguita ogni secondo come stabilito dalla setInterval, anche dopo il completamento della response HTTP.

Queste osservazioni sono correlate alla questione degli headers HTTP. Se apriamo uno strumento di sviluppo Web, come ad esempio Firebug su Firefox, possiamo verificare il valore degli headers della risposta HTTP. Molto probabilmente avremmo qualcosa del genere

 
headers_01

Figura 1 – Headers HTTP della risposta di Node.js

 

Da cui vediamo che, oltre all’ header specificato in maniera esplicita dal nostro codice (ovvero "Content-Type": "text/plain"), abbiamo anche i seguenti headers

 

 

questo ci dice innanzitutto che Node.js gestisce automaticamente alcuni degli header della risposta, che vengono ritornati al client usando i valori di default (quelli qui sopra). Il motivo della scelta riguarda sia le prestazioni del server, sia della trasmissione dei dati. Gli headers connection e transfer-encoding sono stati introdotti col protocollo HTTP 1.1. Il primo mantiene “viva” la connessione TCP/IP, permettendo così di usare la stessa connessione HTTP sopra TCP/IP nell’ambito di più richieste consecutive. Ciò aumenta le performance perché riduce il numero di volte che la connessione client-server viene aperta. Il secondo riguarda la modalità di trasferimento dei contenuti: il valore “chunked” indica che stiamo ricevendo i dati in modalità “streaming”, cioè man mano che sono disponibili. Questo modo di trasmettere i dati è opposto alla tecnica di “buffering”, che invece richiede al server di bufferizzare i dati prima di trasmetterli al client.

L’esempio presentato a pagina precedente è uno snippet a scopo puramente didattico, che non riesce a sfruttare appieno le potenzialità del protocollo HTTP 1.1. È anche per questo motivo che abbiamo sbirciato la configurazione dell’header e verificato la presenza delle voci “Connection” e “Transfer-Encoding”. Ciò fa capire che Node.js è potenzialmente in grado di trasmettere i dati man mano che diventano disponibili, evitando così di appesantire il server. Questa caratteristica sarà più evidente quando useremo l’oggetto socket, che al momento non è disponibile nella versione base di Node.js (versione 0.8.8 alla data di quest’articolo), ma richiede di essere installato manualmente. Nelle prossime lezioni vedremo come installare il modulo socket.io, e inizieremo a vedere come Node.js permetta di sfruttare il protocollo WS nella comunicazione client-server.

 

 

Facci sapere cosa ne pensi!

  1. Domenico Melisi says

    Per qualche ragione il mio server si blocca dopo il .end
    e mi genera questo errore

    events.js:154
    throw er; // Unhandled ‘error’ event
    ^

    Error: write after end
    at ServerResponse.OutgoingMessage.write (_http_outgoing.js:426:15)
    at null._repeat (C:\Users\Domenico\Desktop\Prove Node.js\server3.js:10:10)
    at wrapper [as _onTimeout] (timers.js:275:11)
    at Timer.listOnTimeout (timers.js:92:15)

Facci sapere cosa ne pensi!

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *