‫-: Va bene, ora lavoriamo davvero con i flussi.
‫E ancora, iniziando creando un nuovo file.
‫Va bene. Ora diciamo che per
‫qualche motivo nella nostra applicazione, dobbiamo leggere un file di testo di
‫grandi dimensioni dal file system e quindi inviarlo al client.
‫Quindi come lo faremmo?
‫Bene, ci sono diversi modi e ne
‫esploreremo alcuni partendo da quello più
‫elementare e arrivando fino al modo migliore per farlo.
‫Ok, quindi la prima cosa è richiedere il pacchetto
‫del file system proprio come prima, e anche il modulo HTTP.
‫Lascia che ora ti mostri un bel trucco,
‫quindi creiamo un server come questo.
‫Quindi, richiedi il pacchetto HTTP, e poi da qui
‫possiamo chiamare subito createServer. Quindi proprio così.
‫Ok, quindi il risultato della richiesta di HTTP è
‫l'oggetto HTTP e lì possiamo usare createServer.
‫Proprio così, e poi salvalo in una variabile.
‫Quindi questo è un altro modo per creare un nuovo
‫server scrivendo anche un po' meno codice.
‫Ok, proprio come prima, ora elenchiamo l'evento di
‫richiesta e specifichiamo qui la nostra richiamata.
‫Quindi, la prima soluzione che useremo è
‫la più semplice e diretta.
‫Che è semplicemente leggere il file in una variabile e
‫poi, una volta fatto, inviarlo al client
‫nel modo in cui sappiamo già come farlo.
‫Quindi questo è molto semplice e lasciami scrivere
‫un commento qui per questo. Quindi soluzione
‫uno, e così fs. readFile, quindi di nuovo il nostro file di prova.
‫E poi, una volta che è pronto, chiamiamo la nostra funzione di
‫callback in cui abbiamo accesso ai dati.
‫Ma prima gestiamo l'errore.
‫Quindi, ad esempio, nel caso in cui il file non esista,
‫e in tal caso registriamo semplicemente l'errore nella console.
‫Ma in caso contrario, inviamo semplicemente questi dati al cliente.
‫Quindi usiamo l'oggetto risposta proprio come abbiamo fatto
‫prima molte volte, e poi . fine e i dati.
‫Quindi, salvalo e questa è la prima e
‫la soluzione più semplice, giusto?
‫Ma prima di poterlo testare, dobbiamo effettivamente avviare
‫anche un server, giusto? Quindi usiamo listen per farlo.
‫E la porta, la stessa di prima, quindi localhost e la
‫nostra funzione di callback.
‫Ok, quindi vediamo se funziona davvero.
‫E ovviamente no, perché in realtà non ho nemmeno
‫avviato l'applicazione.
‫Quindi ora dice ascolto, e ora vediamo cosa
‫succede qui.
‫E qui andiamo. Quindi questo file è
‫enorme, ha Node. js è il migliore scritto al
‫suo interno tipo 10000 volte o qualcosa del genere, quindi ci vuole
‫molto tempo prima che si carichi completamente. E non siamo davvero interessati
‫a caricare tutto, quindi fermiamolo qui e torniamo
‫al nostro codice. Quindi funziona bene, la soluzione
‫che abbiamo qui in questo caso, ma il problema
‫è che con questa soluzione, il nodo
‫dovrà effettivamente caricare l'intero file in memoria,
‫perché solo dopo che è pronto, può inviare
‫quei dati . Ora questo è un problema quando
‫il file è grande e anche quando ci sono un sacco di richieste
‫che colpiscono il tuo server. Poiché il processo
‫del nodo esaurirà molto rapidamente le risorse e la tua
‫app smetterà di funzionare, tutto si bloccherà e i tuoi utenti
‫non saranno felici, credimi. Quindi questa soluzione qui
‫funziona quando stiamo semplicemente creando qualcosa di piccolo
‫localmente solo per noi stessi, ad esempio.
‫Ma in un'applicazione pronta per la produzione, non è possibile utilizzare un
‫pezzo di codice come questo. Va bene? Quindi passiamo alla nostra
‫seconda soluzione. E in
‫quella soluzione, utilizzeremo effettivamente i flussi.
‫Ok, allora commentiamo questa parte e
‫passiamo alla soluzione numero due.
‫E l'idea qui è che in realtà
‫non abbiamo davvero bisogno di leggere questi dati dal file in una variabile, giusto?
‫Non abbiamo bisogno di questa variabile. Quindi, invece di
‫leggere i dati in una variabile e dover archiviare
‫quella variabile in memoria, creeremo semplicemente un flusso leggibile.
‫Quindi, quando riceviamo ogni blocco di dati,
‫lo inviamo al client come
‫risposta che è un flusso scrivibile, ricorda.
‫Quindi lascia che ora ti mostri come possiamo usare gli stream.
‫Quindi creiamo una variabile, chiamiamola leggibile qui, e poi
‫di nuovo dal file system, usiamo createReadStream
‫Quindi questo ovviamente piccolo. E ora il nome del file che
‫stiamo cercando di leggere. Quindi questo è di nuovo, file di prova. testo.
‫Ok, perfetto. Quindi questo ora crea un flusso dai
‫dati che si trovano in questo file di testo, che possiamo
‫quindi consumare pezzo per pezzo. Quindi pezzo per pezzo.
‫E come lo facciamo? Bene, ricorda
‫dall'ultima lezione, che ogni volta che c'è un
‫nuovo pezzo di dati che possiamo consumare, un flusso
‫leggibile emette l'evento dati. Ok, quindi possiamo ascoltarlo,
‫proprio come abbiamo appreso nella conferenza degli eventi.
‫Così leggibile. on, data e poi la nostra funzione di callback.
‫E nella nostra funzione di callback, abbiamo accesso a quel pezzo
‫di dati, quindi a quel pezzo.
‫Permettetemi di chiamarlo chunk qui nella nostra
‫funzione di callback e così ora possiamo gestire questo pezzo di dati.
‫E quello che faremo con
‫questo pezzo di dati, con questo pezzo, è
‫effettivamente scriverlo su un flusso scrivibile, che è la risposta.
‫Quindi, ris. scrivi, questo pezzo. Va bene?
‫Quindi ricorda ancora che questa risposta è
‫un flusso scrivibile. Quindi, proprio come ho
‫detto nel video precedente, giusto? E così ora possiamo usare
‫il metodo di scrittura per inviare ogni singolo pezzo di dati in quel flusso.
‫Ok, e con questo stiamo effettivamente
‫trasmettendo il contenuto dal file direttamente al client.
‫Ok, hai capito la differenza?
‫Quindi, prima, scriviamo tutto in una volta in una variabile
‫e, una volta pronta, abbiamo inviato l'intero pezzo di
‫dati al client. Ma in questa
‫situazione, con il flusso, è diverso.
‫Stiamo effettivamente trasmettendo il file, quindi leggiamo una
‫parte del file e, non appena è
‫disponibile, lo inviamo direttamente al client, utilizzando il metodo di scrittura del
‫flusso di risposta. Quindi, quando il pezzo
‫successivo sarà disponibile, quel pezzo verrà inviato e fino a
‫quando l'intero file non verrà letto e inviato in streaming al client.
‫Ok, ora, per finire, dobbiamo anche gestire l'evento
‫quando tutti i dati sono stati letti.
‫Quindi, quando lo stream ha praticamente finito di leggere i
‫dati dal file.
‫Quindi, in quel caso, verrà emesso l'evento finale,
‫e quindi non appena ciò accadrà ciò che faremo
‫è fare res. fine, ok? E abbiamo usato
‫questo prima, quindi chiamando fine sulla risposta, l'abbiamo fatto prima, giusto?
‫E ora, in realtà, ha più senso, perché ancora una
‫volta, anche la risposta è un flusso e il
‫metodo finale segnala che non verranno più scritti dati
‫su questo flusso scrivibile, ok?
‫Quindi quassù tutto ciò che abbiamo fatto è stato effettivamente usare res. terminare con i dati
‫in esso. Quindi non abbiamo fatto streaming, tutto
‫ciò che abbiamo fatto è stato alla fine inviare alcuni dati.
‫Ora, in questo caso, non stiamo
‫passando nulla in questo metodo end, perché abbiamo già inviato tutti
‫i dati utilizzando res. write, pezzo per pezzo,
‫e quindi quando il flusso leggibile ha finito
‫di leggere il suo file, tutto ciò che dobbiamo fare è quindi
‫segnalare che siamo pronti usando res. finisci così, ok?
‫Quindi abbiamo sempre bisogno di usare questi dati e questo evento finale qui uno dopo
‫l'altro in questo modo. Perché altrimenti,
‫la risposta in realtà non verrà
‫mai inviata al client. Ok, quindi senza questo
‫pezzo qui, l'intera soluzione non funzionerebbe davvero, ok?
‫Quindi ora chiudiamo questo, ricominciamo e
‫leggiamo di nuovo, così vedrai che funziona
‫di nuovo, ok? Ora questa volta senza i problemi che abbiamo
‫avuto con la prima soluzione. Fermiamoci qui e torniamo
‫al nostro codice, perché voglio mostrarvi ora
‫che c'è un altro evento che possiamo ascoltare
‫su un flusso leggibile, che è l'evento di errore.
‫Così leggibile. on('error') e in questa funzione
‫di callback abbiamo accesso all'oggetto errore.
‫Va bene, in questo caso registreremo questo errore nella console,
‫quindi invieremo il risultato del file non trovato.
‫E possiamo anche impostare il codice di stato su
‫un errore, ad esempio 500. Quindi di solito è impostato
‫automaticamente su 200 che significa ok, ma in questo caso abbiamo un errore del
‫server, il che significa che vogliamo restituire il codice 500.
‫Va bene, quindi ora...
‫In realtà devo smettere di nuovo.
‫Quindi vediamo cosa succede ora.
‫Oh, abbiamo già un errore proprio
‫qui, res. lo stato non è una funzione. E sì,
‫in realtà il suo statusCode. Quindi questo è il
‫modo in cui lo scrivi in express, quindi sono già abituato a scrivere
‫express così tanto, quindi express è un nodo. js che useremo nel resto del
‫corso e in express lo
‫fai in questo modo, e quindi questo
‫era il problema. Quindi sono già un po' troppo
‫abituato a scrivere express.
‫Quindi torniamo indietro, e sì, ora vediamo il file non trovato, e
‫se apriamo gli strumenti di sviluppo, vedi il nostro codice di errore 500 che abbiamo
‫appena inviato prima, e se andiamo alla nostra scheda di rete,
‫proviamo di nuovo, hai anche il codice di stato qui.
‫Quindi proprio come abbiamo visto in uno dei video precedenti in
‫un'altra sezione in realtà. Quindi è così che possiamo
‫ispezionare questo tipo di cose nella scheda di rete.
‫Va bene, quindi risolviamolo qui, salviamolo e ok, quindi
‫funziona di nuovo perfettamente ma c'è ancora un problema con
‫questo approccio che ti ho
‫appena mostrato. E il problema è
‫che il nostro flusso leggibile, quindi quello che
‫stiamo usando per leggere il file dal disco, è molto molto
‫più veloce dell'invio effettivo del risultato con il flusso
‫scrivibile di risposta sulla rete. E questo travolgerà il flusso
‫di risposta, che non può gestire tutti questi dati in arrivo così velocemente.
‫E questo problema si chiama contropressione.
‫Ed è un vero problema che può capitare in situazioni reali.
‫Quindi, in questo caso, si verifica una contropressione quando la
‫risposta non può inviare i dati alla stessa velocità con cui
‫li riceve dal file, ha senso?
‫Quindi dobbiamo risolvere quella
‫soluzione e trovarne una ancora migliore.
‫Quindi, creeremo la soluzione tre,
‫e questa è in
‫realtà l'ultima, ok? Quindi non più soluzioni di tre.
‫Quindi il segreto qui è usare effettivamente quell'operatore di tubi
‫che ho menzionato nell'ultimo video, ok?
‫Quindi l'operatore pipe è disponibile su tutti i flussi leggibili e
‫ci consente di convogliare l'output di un
‫flusso leggibile direttamente nell'input di un flusso scrivibile, ok?
‫E questo risolverà il problema della contropressione perché
‫gestirà automaticamente la velocità fondamentalmente dei dati
‫in entrata e la velocità dei dati in uscita.
‫Ok, quindi otteniamo il nostro flusso leggibile qui.
‫Ok, questo è il nostro flusso leggibile, e
‫ora tutto ciò che dobbiamo fare è prendere il nostro flusso leggibile,
‫utilizzare il metodo pipe su di esso, quindi inserire un flusso scrivibile e
‫questa è la risposta. Ed è proprio così.
‫Questo è tutto ciò che dobbiamo fare per questa soluzione, ok?
‫Quindi funziona sempre così, lascia che
‫lo scriva qui come commento. Quindi abbiamo bisogno di una fonte leggibile
‫fondamentalmente, ok quindi di nuovo questo è solo per spiegartelo,
‫quindi possiamo usare la pipe su di esso, e
‫qui dovremo mettere una destinazione scrivibile. Quindi è da qui che
‫provengono i nostri dati, e deve essere un
‫flusso leggibile, e quei dati che possiamo quindi convogliare in una destinazione scrivibile.
‫Quindi in questo caso la nostra destinazione è la risposta, ok?
‫Ora questo flusso qui può effettivamente essere anche un flusso duplex
‫o di trasformazione, ma ciò che conta è che
‫possiamo scrivere nel flusso. E la risposta,
‫ovviamente, è un tale flusso. Quindi possiamo ovviamente scrivere
‫alla risposta che verrà inviata al cliente, ok?
‫Quindi l'operatore del tubo risolve automaticamente il problema
‫della contropressione che avevamo in precedenza.
‫Ed è anche una soluzione molto più
‫elegante e diretta. Quindi quello che abbiamo
‫fatto qui prima era solo mostrarti tutti i modi
‫in cui possiamo usare i metodi e gli eventi di flusso per creare
‫questo tipo di soluzione e ovviamente hanno molti casi d'uso,
‫ma in un problema come questo, il tubo operatore è
‫in realtà la soluzione migliore. Dietro le quinte fa qualcosa di
‫simile qui in realtà, ma ancora
‫una volta in un modo molto più diretto per noi
‫di scrivere, perché gestisce tutte le cose
‫internamente dietro le quinte. Quindi credo che la pipe qui
‫sia in realtà il modo più semplice di consumare e scrivere flussi, a
‫meno che, ovviamente, come ho detto, non abbiamo bisogno
‫di soluzioni più personalizzate. E poi, dobbiamo usare
‫questi strumenti più complicati come questi eventi e metodi
‫che ti ho mostrato prima. Va bene, quindi
‫solo per finire, lasciamo qui il processo, ricominciamo e, naturalmente,
‫vediamo se funziona ancora, cosa che fa.
‫E così, il nostro lavoro è finito qui. Quindi abbiamo finito con questa
‫lezione e siamo pronti per passare direttamente alla prossima.