Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Event loop e libuv in Node.js: evitare le cattive pratiche

Programmare applicazioni concorrenti con Node.js, sfruttando le promise e il costrutto async/await per evitare il callback hell.
Programmare applicazioni concorrenti con Node.js, sfruttando le promise e il costrutto async/await per evitare il callback hell.
Link copiato negli appunti

Com'è noto,

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

opera su un singolo thread.

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

utilizza la libreria

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

per sfruttare questa
caratteristica e gestire l’esecuzione attraverso l’

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

, che
consente di eseguire

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

.

La caratteristica principale di libuv che permette a Node.js di supportare
l’esecuzione asincrona di JavaScript, è sostanzialmente la sua gestione
degli eventi delle principali operazioni di I/O del kernel, come i socket
TCP e UDP, la risoluzione DNS, le operazioni sul file system e sui file, e
gli eventi del file system stesso.

In libuv tutte queste operazioni sono asincrone, ma l’aspetto più
importante di questa libreria è che tramite epoll, kqueue, IOCP ed eventi
fornisce a Node.js le fondamenta per costruire il suo event loop.

La

documentazione sull’Event Loop

illustra le fasi di questo ciclo, ma rivela anche un problema insito nel
design delle API di Node.js: accanto a metodi tradizionalmente asincroni,
esistono infatti anche metodi sincroni che, di fatto, bloccano l’event loop in una determinata fase, impedendogli
di proseguire nell’esecuzione delle fasi successive.

Un tipico esempio è il metodo del modulo core fs, che gestisce
le operazioni sui file e sul file system. Fintanto che i contenuti di un
file sono già predeterminati e le sue dimensioni sono fisse, note e
prestabilite (come nel caso della lettura di una chiave privata e di un

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

), questo metodo sincrono non ha un impatto negativo
sull’event loop. Al contrario, e soprattutto quando la lettura sincrona
viene esposta nel frontend tramite

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

(come nel caso delle immagini),
si possono avere gravi ripercussioni sulla performance fino alla messa in
atto di un

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

che non solo blocca l’esecuzione di Node, ma va anche
ad impattare sulla performance globale del server che ospita il sito o
l’app.

Per evitare il callback hell insito nella sintassi
stessa dei metodi asincroni, si possono adottare le caratteristiche più recenti di
ECMAScript, come le

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

e il costrutto

[!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

che mantengono
inalterata l’asincronicità delle operazioni fornendo però una sintassi che
ci permette di evitare l’annidamento di funzioni su funzioni.

Ad esempio, possiamo creare la seguente classe di utility che fa uso delle
Promise:

'use strict';
const path = require('path');
const fs = require('fs');
const ABSPATH = path.dirname(process.mainModule.filename);

class Files {
    static read(path, encoding = 'utf8') {
      return new Promise((resolve, reject) => {
        let readStream = fs.createReadStream(ABSPATH + path, encoding);
        let data = '';
        readStream.on('data', chunk => {
            data += chunk;
        }).on('end', () => {
            resolve(data);
        }).on('error', err => {
            reject(err);
        });
      });
    }

    static create(path, contents) {
        return new Promise((resolve, reject) => {
            fs.writeFile(ABSPATH + path, contents, (err, data) => {
                if(!err) {
                    resolve(data);
                } else {
                    reject(err);
                }
            });
        });
    }
    static remove(path) {
        return new Promise((resolve, reject) => {
            fs.unlink(ABSPATH + path, err => {
                if(!err) {
                    resolve(path);
                } else {
                    reject(err);
                }
            });
        });
    }

    static exists(path) {
        return new Promise((resolve, reject) => {
            fs.access(ABSPATH + path, fs.constants.F_OK, err => {
               if(!err) {
                   resolve(true);
               } else {
                   reject(err);
               }
            });
        });
    }
}
module.exports = Files;

Quindi possiamo coniugare il modello delle Promise con il costrutto async/await:

'use strict';
const app = require('expresss')();
const Files = require('./lib/Files');

app.get('/api/file', async (req, res) => {
    try {
        let data = await Files.read('/log/file.log');
        res.send(data);
    } catch(err) {
        res.sendStatus(500);
    }
});
app.listen(8000);

Come si può notare, tramite l’uso combinato delle Promise e del costrutto async/await abbiamo evitato il callback hell anche grazie ad un'attenta separazione e delegazione dei compiti nel nostro codice.

Conclusione

Abbiamo visto come l’event loop di Node.js sia basato su operazioni asincrone e come tale asincronicità vada preservata in modo da non interrompere lo stesso event loop.

Questo articolo contiene link di affiliazione: acquisti o ordini effettuati tramite tali link permetteranno al nostro sito di ricevere una commissione nel rispetto del codice etico

Ti consigliamo anche