Lotrèk
24 November 2020

Come migliorare le prestazioni della tua web app grazie ai Web Worker


Andrea  profile image
Human:
Andrea 
Tempo
di lettura
5'

In questo tutorial parleremo di come migliorare le prestazioni della tua web app grazie ai Web Worker

Nel nostro ultimo progetto PharmaCity ci siamo imbattuti in un problema che può essere fonte di grattacapi quando si usano librerie o framework come Vue.js o Angular: utilizzare un componente pesante da creare e renderizzare, di solito perché esegue attività complesse.

Il nostro caso specifico è stato l'inserimento di un testo RTF in un componente ad hoc per renderizzarlo, che i contenutisti possono utilizzare per inserire qualsiasi tipo di testo formattato come elenchi, immagini, virgolette, grassetto, corsivo... Quando ottieni il contenuto RTF dal backend del nostro sistema attraverso una API Rest, questo tipo di dato ha una propria struttura. Per rendere tali dati in HTML, è necessario renderizzarli attraverso l'apposito metodo.

Fin qui niente di speciale. Il rendering però si è rivelato un processo pesante, che stava iniziando a essere evidente durante il rendering di molti di questi componenti con una discreta quantità di contenuto. Il motivo è che l'esecuzione JavaScript predefinita viene eseguita nel thread principale, che è il blocco dell'interfaccia utente. Come possiamo risolvere questo problema? Utilizzando un Web Worker per l'attività di rendering di testo RTF! I Web Worker infatti vengono eseguiti in un thread separato e non bloccano l'interfaccia utente, ed è proprio quello che ci serve!

Come potete vedere dallo schema qua sopra i Web Worker vengono eseguiti in un thread separato rispetto a quello principale e la comunicazione avviene tramite uno scambio di messaggi, come vedremo in seguito con un esempio.

Senza addentrarci nelle specifiche del nostro componente, utilizziamo un caso d'uso molto più semplice ma che renda l'idea delle potenzialità dei Web Worker, andando a sviluppare un componente che esegue una pesante operazione come il calcolo del numero di Fibonacci e cerchiamo di migliorare l'esperienza utente con i Web Worker. Utilizzeremo per questo esempio Vue.js.

Il nostro codice avrà un modulo per il calcolo di Fibonacci  (fibonacci.js)

let fibonacci = (num) => {
  if (num <= 1) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}
export default fibonacci

e una implementazione Vue.js molto semplice

<template>
  <div id="app">
    <h1>Fibonacci</h1>
    <input v-model.number="inputNumber" type="number" placeholder="Insert a number"/>
    <button @click="calculate()">Calculate</button>
    <div v-if="result" class='result'>Result: {{result}}</div>
  </div>
</template>
<script>
import fibonacci from "./fibonacci";
export default {
  name: 'App',
  data () {
    return {
      inputNumber: 0,
      result: null
    }
  },
  methods: {
    calculate() {
      this.result = fibonacci(this.inputNumber);
    }
  }
}
</script>

Se provate a far girare questo codice, vedrete che con numeri alti la UI comincia a non rispondere più ai comandi dell'utente e la pagina si blocca inesorabilmente. La funzione fibonacci infatti gira sul thread principale e all'aumentare dell'input, aumenta il suo tempo di esecuzione. Tralasciando le possibili ottimizzazioni di questa funzione che volutamente deve eseguire un'operazione bloccante, proviamo a spostare tutto il calcolo di Fibonacci in un Web Worker (fibonacci.worker.js)

import fibonacci from "./fibonacci";
self.onmessage = async function (e) {
  self.postMessage(fibonacci(e.data));
};

e modifichiamo solo la parte JavaScript del nostro componente per fargli usare questo Web Worker.

import Worker from './fibonacci.worker'
const worker = new Worker();
export default {
  name: 'App',
  data () {
    return {
      inputNumber: 0,
      result: null
    }
  },
  methods: {
    calculate() {
      worker.onmessage = ({data}) => {
        this.result = data
      };
      worker.postMessage(this.inputNumber);
    }
  }
}

Per far girare il tutto occorre installare il plugin WebPack worker-loader

yarn add worker-loader -D

e configurarlo in Vue.js all'interno del file vue.config.js

module.exports = {
  configureWebpack: (config) => {
    config.output.libraryExport = 'default'
    config.module.rules = [
      {
        test: /\.worker\.js$/i,
        use: [
          {
            loader: 'worker-loader',
            options: {
              inline: 'no-fallback',
            },
          }
        ]
      },
      ...config.module.rules
    ]
  }
}

In questo modo diciamo a WebPack di processare tutti i file *.worker.js con il plugin worker-loader che abbiamo installato precedentemente.

Riavviando l'applicazione si può vedere che l'esecuzione del processo più pesante (in questo caso il calcolo del numero di Fibonacci) è demandata a un Web Worker e l'interfaccia non si blocca. Trovate il codice completo su GitHub. Per approfondimenti vi lascio alcuni link utili per approfondire il tema dei Web Worker.

Web Workers API documentation
Use Web Workers in your Vue.js Components for Max Performance
How to test Web Workers with Jest

Volete saperne di più sui Web Worker e sui lavori della nostra web development agency? Di seguito alcuni link utili per l'approfondimento!

Continuous integration e continuous deployment
Come tenere sotto controllo la pesantezza dei file Javascript


Vuoi saperne di più?

Iscriviti e riceverai gratuitamente sulla tua mail news, insight e report mensili sui trend del momento.

Registrandoti confermi di accettare la nostra privacy policy.


Condividi

Responsabile dello sviluppo, passo la mia vita tra i tasti meccanici e quelli della 6 corde. Quando parenti e amici non chiamano perchè "non gli va il computer" vado a caccia di birre e scatti interessanti.

Articoli Correlati

 Invio email in corso, yeah!
Richiesta inviata
Il tuo indirizzo email risulta già iscritto
C'è stato un problema riprova più tardi