back to top

Introduzione a Node.js

In questa guida parleremo di Node.js (o semplicemente Node), introducendo alcuni dei concetti chiave, indispensabili per capire il suo funzionamento. Data l’ampiezza e la complessità dei temi che verranno discussi, si tratterà semplicemente di un’introduzione. Per maggiori informazioni e dettagli, si consiglia di consultare la documentazione ufficiale. Nel resto degli articoli faremo riferimento alle versioni v8.x.x, ovvero l’ultima major release disponibile al momento della stesura di questa guida.

Cos’è Node.js?

Node.js è una piattaforma open-source che permette di eseguire applicazioni scritte in Javascript al di fuori del browser. Per questo motivo, Node.js incorpora al suo interno il motore Javascript V8, realizzato da Google e usato anche all’interno del browser Chrome. (In realtà è anche possibile usare Chakra, il motore Javascript di Microsoft, al posto di V8) V8 permette di convertire ed eseguire il codice scritto in linguaggio Javascript. Prima dell’avvento di Node.js, Javascript era usato principalmente all’interno del browser per scrivere degli script da eseguire all’interno delle pagine web. Grazie anche a Node.js, oggi Javascript è uno dei linguaggi di programmazione più diffusi e usato in svariati ambiti. Insieme a Node.js è stato introdotto anche NPM, un package manager per Javascript che permette agli sviluppatori di organizzare, riutilizzare, pubblicare e condividere il codice sorgente. Prima di continuare con il resto della guida, vi consiglio di leggere questo articolo introduttivo su NPM.

Introduzione a Node.js

Node.js, io.js, Ayo.js

Come già detto, Node.js è un progetto open-source. Per questo motivo è possibile per chiunque avviare un nuovo progetto a partire dal codice sorgente di Node.js. È proprio così che nel 2014 è nato io.js, con "l’obiettivo di raggiungere un ciclo di sviluppo più rapido e prevedibile". io.js era compatibile con l’ecosistema NPM. Dopo la versione 3.x.x, io.js si è riunito con il progetto Node.js (a partire dalla versione 4.x). Ad Agosto 2017, a causa di incomprensioni interne alla comunità che gestisce Node.js, è nato un nuovo progetto: Ayo. In attesa di nuovi sviluppi, nel corso di questa guida faremo comunque riferimento alla versione 8 di Node.js.

Perché usare Node.js

Node.js ha riscontrato fin da subito un grande interesse da parte degli sviluppatori fino a diventare un progetto di enorme successo. Sono ormai numerose le compagnie che lo utilizzano in produzione. Tra queste, solo per citare i nomi di alcune delle più importanti, possiamo menzionare Paypal, Netflix, eBay, Microsoft e Walmart che ha anche realizzato Hapi, uno dei framework più popolari per realizzare applicazioni web usando Node.js.

Node.js, grazie alla sua architettura, è ideale per applicazioni che richiedono frequenti operazioni di I/O. Oggi viene comunque utilizzato in diversi ambiti. È possibile adoperarlo per:

Sviluppare applicazioni web e REST api

Express Node.js Framework per applicazioni web

Node.js mette a disposizione tutti gli strumenti per realizzare un server HTTP più o meno complesso. A questo scopo, vengono messi a disposizione degli sviluppatori i moduli http, https e http2. Quest’ultimo è stato introdotto a partire dalla versione 8.4 anche se in maniera sperimentale. Inoltre sono stati realizzati vari framework, come Hapi, che abbiamo già citato sopra, Sails, Koa e Express, che semplificano la realizzazione di applicazioni web e REST api. Node.js è anche impiegato dalla popolare piattaforma open-source Ghost, usata specialmente per la creazione di blog e magazine online.

Script da eseguire tramite linea di comando

Semplice script scritto in Javascript

Node.js consente di realizzare script da lanciare tramite linea di comando, permettendo agli sviluppatori di sfruttare semplicemente Javascript per la realizzazione di qualsiasi tipo di strumento da usare nella shell.

Sviluppare applicazioni Desktop cross-platform

Electron Framework per applicazioni Desktop cross-platform

Node.js è uno dei componenti fondamentali di Electron, il popolare framework open-source sviluppato da GitHub, che permette di usare HTML, CSS e Javascript per la realizzazione di applicazioni Desktop eseguibili su Windows, Linux e MacOs.

Sviluppare applicazioni per robot, droni e IoT

Cyclon.js

Usato inizialmente per lo più a livello hobbistico, oggi Node.js è considerato una delle piattaforme ideali per la realizzazione di applicazioni in ambito IoT. Anche in questo settore sono nati numerosi progetti. Chi volesse cimentarsi nello sviluppo di qualche applicazione, può dare un’occhiata a Cylon.js e Johnny-Five.

Sviluppare sistemi di chat e streaming audio/video

Socket.io framework per websocket

Un altro ambito in cui Node eccelle, è lo sviluppo di sistemi di chat e streaming audio/video. In uno dei prossimi articoli, vedremo come realizzare una semplice chat usando il modulo nativo tcp. Librerie come Socket.io consentono, inoltre, di sviluppare applicazioni di messaggistica istantanea utilizzabili nel browser. Grazie a numerosi moduli e librerie disponibili online, è anche possibile creare dei Chat Bot più o meno complessi per applicazioni come Telegram, Facebook Messenger, Twitter, Slack, Viber ecc.

Come funziona Node.js in breve

Il motivo per cui Node.js ha raggiunto una tale diffusione e popolarità in diversi ambiti è da attribuire alla sua architettura. Node.js si basa sulla tecnica della programmazione a eventi e sul modello di I/O asincrono non bloccante. Cerchiamo di chiarire cosa vuol dire. Come abbiamo già accennato, Node.js si affida al motore Javascript V8 per l’esecuzione del codice della nostra applicazione. V8 può eseguire una sola istruzione per volta. L’utilizzo della programmazione a eventi e dell’esecuzione asincrona danno tuttavia l’impressione che le applicazioni eseguano più istruzioni contemporaneamente. In realtà viene sempre processata un sola istruzione alla volta.

In altre tecnologie, quando viene richiesta una risorsa esterna, per esempio nel caso di lettura/scrittura di un file o di accesso a un database, viene invocata una funzione e il programma si blocca in attesa che tale funzione venga terminata.

In Node.js, invece, quando viene richiesta una certa risorsa, questa viene recuperata in modo asincrono e Node.js può continuare l’esecuzione del resto del codice. Solitamente, viene indicata quale funzione invocare una volta che la risorsa è stata recuperata. Node.js delega il sistema operativo sottostante e continua ad eseguire le altre istruzioni. Quando la risorsa è stata recuperata, Node.js viene avvertito dal sistema operativo che genera un evento il quale viene inserito in una coda. Ad ogni iterazione di un ciclo di gestione degli eventi, Node.js estrae dalla coda (in modalità First In First Out, il primo evento in ingresso è il primo ad essere prelevato) un evento alla volta e, se V8 non sta già processando altre istruzioni, viene eseguita la funzione corrispondente.

Consideriamo il seguente esempio. Importiamo il modulo nativo fs che useremo per leggere un file. (Parleremo approfonditamente della funzione require e del modulo fs nei prossimi articoli.) Chiediamo a Node.js di leggere il contenuto del file node_script.js presente all’interno della directory corrente. Alla funzione readFile(), passiamo come secondo argomento una funzione che verrà eseguita nel momento in cui è stata terminata la lettura del file ed è disponibile il suo contenuto. Quest’ultimo sarà passato alla funzione callback come secondo argomento. Nel caso non ci sia stato nessun errore, stampiamo a video il contenuto del file. (‘data’ è un oggetto di tipo Buffer che permette di lavorare con dati binari. Per visualizzare i caratteri del file usiamo il metodo buffer.toString())

// file: esempio_callbacks.js

const fs = require('fs');

console.log('1) Sto per leggere un file...')

fs.readFile('./node_script.js', (error, data) => {
  if (error) {
    throw error;
  }
  console.log('3) Contenuto file:nn', data.toString());
});

console.log('2) Lettura file in corso...');

Abbiamo inserito il frammento di codice all’interno di un file esempio_callbacks.js. Abbiamo quindi lanciato nella shell il comando node <nome_del_file_da_eseguire>. Potete vedere l’output nell’immagine sottostante.

Risultato esecuzione funzione fs.readFile.jpg

Node.js inizia ad invocare la prima funzione console.log(), esegue poi la funzione fs.readFile(). A questo punto invece di bloccarsi in attesa che venga recuperato e letto il file dal disco, il programma continua la sua esecuzione stampando a video il secondo messaggio. Solo quando il contenuto del file è pronto, verrà eseguita la funzione passata come argomento alla funzione fs.readFile(). Verrà a questo punto mostrato il contenuto del file letto.

I diversi componenti di Node.js in breve

Vediamo ora in maniera veloce e superficiale quali sono i diversi componenti interni di Node.js. A tal proposito, faremo riferimento all’immagine riportata qui in basso.

Architettura di Node.js

Node.js permette di scrivere le applicazioni in linguaggio Javascript fornendo un API completa e ben documentata. Analizzando il codice di Node.js, si nota però che, oltre ai moduli Javascript, sono presenti diversi moduli scritti in C++. Facendo riferimento all’esempio appena visto, quando chiamiamo la funzione fs.readFile(), Node.js eseguirà ad un certo punto del codice scritto in C++ che permetterà di leggere il file richiesto. Un altro componente chiave è il motore V8, anch’esso scritto in C++, che permette di convertire ed eseguire il codice Javascript delle nostre applicazioni. Altro elemento estremamente importante è la libreria libuv, scritta in C. Libuv è ciò che rende possibile il modello di I/O asincrono soprattutto grazie a quello che viene definito "Event-loop" (Riprenderemo l’argomento in uno dei prossimi articoli). Abbiamo visto che Node.js affida al sistema operativo l’esecuzioni di varie operazioni come la lettura/scrittura di un file. Libuv viene avvertita periodicamente se il sistema operativo ha terminato il suo compito. A quel punto viene generato un evento che viene inserito in una coda interna alla stessa libreria. Ogni evento viene processato e se V8 non sta eseguendo altre istruzioni, gli verrà passata la funzione callback corrispondente (per esempio se ricordate avevamo passato una funzione come secondo argomento di fs.readFile). In questo modo, mentre una certa risorsa viene recuperata, V8 può continuare ad eseguire altro codice. Nell’immagine sottostante potete osservare quanto appena descritto.

Schema funzionamento Node.js e libuv

Come installare Node.js

Installare Node.js è piuttosto semplice. Per Windows e MacOs, il metodo più semplice è scaricare il programma d’installazione dal sito ufficiale di Node.js. Su MacOs, in alternativa, è possibile usare Homebrew o MacPorts. Per Linux, invece, conviene utilizzare il package manager della distribuzione scelta. Potete trovare maggiori informazioni nella documentazione di Node.js, nella sezione relativa ai package manager di Linux.

pagina download Node.js

Come potete osservare dall’immagine, è possibile eseguire il download di due differenti versioni:

  • LTS (Long Term Support)
  • Current

Per la prima è garantito un supporto di circa 18 mesi. È consigliata per le applicazioni in produzione che si preferisce non aggiornare frequentemente. La versione Current invece riceve aggiornamenti frequenti e presenta tutte le ultime funzionalità sviluppate.

Una volta installata la versione prescelta, assicuratevi che il percorso dell’eseguibile installato sia specificato tra i valori della variabile d’ambiente PATH, adoperata dal sistema operativo per individuare gli eseguibili da lanciare dalla riga di comando.

Per verificare che l’installazione sia stata completata correttamente. Potete aprire la shell ed eseguire il seguente comando:

node -v

Dovreste visualizzare la versione installata così come riportato nell’immagine sottostante.

Come potete vedere è stata installata la versione 8.4.0 di Node.js e la versione 5.3.0 di NPM.

Installare diverse versioni di Node.js con NVM

Può risultare altresì comodo installare contemporaneamente più versioni di Node.js. Per Linux e MacOS, la scelta migliore è rappresentata da nvm, su Windows invece è possibile scegliere fra nodist o nvm-windows. Per maggiori dettagli e informazioni vi consiglio di consultare le rispettive pagine su GitHub.

Conclusioni

Nella prossima lezione, inizieremo a utilizzare Node.js. Inizialmente vedremo come impiegarlo nella shell e ci soffermeremo su alcune funzionalità che possono tornare molto utili durante lo sviluppo di un’applicazione in Javascript.

Pubblicità