Memoization in JavaScript

Memoization è una tecnica usata dalle funzioni per salvare i risultati delle loro esecuzioni per ottimizzare le risorse nelle chiamate successive attraverso funzioni di ordine superiore.

Prima di andare al cuore della questione, dovrebbe capire cosa sono le funzioni di ordine superiore e le chiusure (clausole in inglese, ma suona strano quindi mi atterrò alla chiusura 😅). Se lo sapete già, andate avanti, saltatelo.

Funzioni di ordine superiore

Una funzione di ordine superiore è una che lavora con altre funzioni, o perché le riceve come parametro o perché ne restituisce una.

Se avete mai usato le funzioni map, filter o reduce, allora avete già usato funzioni di ordine superiore. In queste funzioni passiamo una funzione da applicare a ciascuno degli elementi dell’array in un modo particolare in ogni caso.

Fare questo ci aiuta ad astrarre il comportamento della funzione. Un esempio potrebbe essere questo:

https://a.storyblok.com/f/96536/600x576/funcion-orden-superior.jpg

Possiamo vedere come prima si definisce la funzione di ordine superioreQue. Questa funzione restituisce un’altra funzione di confronto, che controlla se il valore passato alla funzione di ordine superiore è minore del valore passato alla funzione che restituisce.

Se vi siete persi 🤯 rileggete più lentamente.

Il prossimo passo è usare la funzione di ordine superiore, quindi memorizziamo nella variabile greaterThan100 ciò che la funzione di ordine superiore restituisce quando le passiamo il valore 100.

E cosa restituisce? Bene, la funzione Compare con 100, che restituirà un booleano.

Infine, quando usiamo la funzione greaterThan100 controlleremo se il valore che le passiamo è maggiore di 100 o meno.

Closures

Le closure sono uno dei concetti chiave in JavaScript. È una funzione interna con accesso alle variabili d’ambiente di un’altra funzione esterna.

Quando una funzione viene invocata in JavaScript, viene creato un nuovo ambiente per quell’invocazione. L’ambiente viene creato per l’invocazione della funzione, non per la funzione stessa. Quando l’esecuzione di una funzione finisce, l’ambiente viene distrutto dal garbage collector.

Tuttavia, se creiamo un collegamento all’ambiente che crea quell’invocazione, non verrà distrutto dopo l’invocazione. Esempio:

https://a.storyblok.com/f/96536/600x526/closure.jpg

La funzione greet è una chiusura, ha accesso all’ambiente della funzione esterna greet me. Quando l’esecuzione della funzione greetme termina, il suo ambiente non viene distrutto perché la variabile greetMeForPol vi ha ancora accesso, abbiamo creato un collegamento all’ambiente, e l’unico modo possibile per accedervi è attraverso la chiusura restituita dalla funzione.

La chiusura è il passaggio tra l’ambiente esterno e interno della funzione greetme. Possiamo accedere solo alle variabili che la chiusura ci permette, il resto è protetto. Questo suona come classi e metodi privati?

Le chiusure ci permettono di esporre le parti che ci interessano in una funzione. Un altro esempio per chiarire un po’ di più quest’ultimo:

https://a.storyblok.com/f/96536/600x1129/closure-2.jpg

In questo esempio abbiamo la funzione Car che trattiamo come se fosse una classe nel paradigma orientato agli oggetti. Esponiamo i metodi getMark, getColor, getKm e dateATurn, ma nient’altro, quindi non possiamo accedere direttamente al mark o a qualsiasi altra cosa che non abbiamo esposto.

Memorizzazione

Per ottenere la cache dei dati in una funzione ci avvantaggeremo delle funzioni di ordine superiore e delle chiusure. È conveniente usare questa tecnica quando chiamiamo ripetutamente una funzione la cui esecuzione può diventare costosa in termini di risorse.

Con la memorizzazione, possiamo chiamare una funzione una seconda volta (passando gli stessi parametri) per restituire lo stesso risultato di prima senza dover eseguire nuovamente il codice.

Vediamolo con un semplice esempio: una funzione che aggiunge 5 a qualsiasi valore passato.

https://a.storyblok.com/f/96536/600x784/memoizacion.jpg

In questo esempio la prima volta che chiamiamo la funzione, il risultato viene calcolato, memorizzato nella cache e restituito. La seconda volta che la chiamiamo passando lo stesso parametro, trova il valore della cache e lo restituisce direttamente.

Anche se l’esempio proposto non è “reale”, immaginate la situazione in cui un dato calcolo richiede circa 500ms e dovete chiamare la funzione in un ciclo su 100 iterazioni. La memorizzazione può essere molto utile, non credi?

Può essere molto utile, non credi?

Lascia un commento

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