Un caso d'uso concreto dei web worker

Nell'ultimo modulo è stata fornita una panoramica dei web worker. I web worker possono migliorare la reattività dell'input spostando JavaScript fuori dal thread principale thread dei worker web separati, così da migliorare l'interazione del sito web a Next Paint (INP) quando hai un lavoro che non richiede l'accesso diretto thread principale. Tuttavia, una panoramica di per sé non è sufficiente e in questo modulo un un caso d'uso concreto per un lavoratore web.

Ad esempio, un sito web che deve eliminare i metadati EXIF da un dell'immagine. Non si tratta di un concetto così vago. Infatti, siti web come Flickr offrono agli utenti un modo per visualizzare i metadati EXIF per conoscere i dettagli tecnici sul le immagini ospitate, ad esempio la profondità di colore, la marca e il modello della fotocamera e altre e i dati di Google Cloud.

Tuttavia, la logica per recuperare un'immagine, convertirla in un ArrayBuffer, l'estrazione dei metadati EXIF potrebbe essere potenzialmente costosa se eseguita interamente sul thread principale. Per fortuna, l'ambito dei worker web consente di svolgere queste operazioni. dal thread principale. Quindi, utilizzando la pipeline di messaggistica del worker web, I metadati EXIF vengono trasmessi al thread principale come stringa HTML. mostrati all'utente.

Come appare il thread principale senza un worker web

Innanzitutto, osserva come appare il thread principale quando svolgiamo questa operazione senza di Google. Per farlo, segui questi passaggi:

  1. Apri una nuova scheda in Chrome e apri i relativi DevTools.
  2. Apri il riquadro del rendimento.
  3. Vai a https://exif-worker.glitch.me/without-worker.html.
  4. Nel riquadro del rendimento, fai clic su Registra nell'angolo in alto a destra della nel riquadro DevTools.
  5. Incolla questo link immagine o un'altra immagine di tua scelta che contenga il file EXIF nel campo e fai clic sul pulsante Ottieni il file JPEG!.
  6. Quando l'interfaccia è compilata con i metadati EXIF, fai di nuovo clic su Record per interrompi la registrazione.
di Gemini Advanced.
Il profiler delle prestazioni che mostra l'attività dell'app di estrazione di metadati delle immagini che si verifica interamente sul thread principale. Ci sono due attività sostanzialmente lunghe: una che esegue un recupero per ottenere l'immagine richiesta e la decodifica, e un'altra che estrae i metadati dall'immagine.
Attività del thread principale nell'app di estrazione di metadati delle immagini. Tieni presente che l'attività si verifica sul thread principale.

Tieni presente che, a parte altri thread che potrebbero essere presenti, come la funzionalità di rasterizzazione thread e così via: tutto ciò che si trova nell'app si verifica nel thread principale. Sulla piattaforma principale questo si verifica quanto segue:

  1. Il modulo accetta l'input e invia una richiesta fetch per ottenere dell'immagine contenente i metadati EXIF.
  2. I dati immagine vengono convertiti in un ArrayBuffer.
  3. Lo script exif-reader viene utilizzato per estrarre i metadati EXIF dai dell'immagine.
  4. I metadati vengono copiati per creare una stringa HTML, che poi compila il campo visualizzatore di metadati.

Ora contrastiamo con un'implementazione dello stesso comportamento, ma utilizzando un modello worker!

Come appare il thread principale con un worker web

Ora che hai visto come si esegue l'estrazione dei metadati EXIF da una file JPEG sul thread principale, dai un'occhiata a come appare quando worker è nel mix:

  1. Apri un'altra scheda in Chrome e apri i relativi DevTools.
  2. Apri il riquadro del rendimento.
  3. Vai a https://exif-worker.glitch.me/with-worker.html.
  4. Nel riquadro del rendimento, fai clic sul pulsante Registra in alto a destra. nel riquadro DevTools.
  5. Incolla questo link immagine nel campo e fai clic sul pulsante Ottieni quel file JPEG!.
  6. Quando l'interfaccia viene completata con i metadati EXIF, fai clic sul pulsante Registra di nuovo per interrompere la registrazione.
di Gemini Advanced.
Il profiler delle prestazioni che mostra l'attività dell'app di estrazione di metadati delle immagini che si verifica sia sul thread principale sia su un thread di worker web. Anche se ci sono ancora attività lunghe sul thread principale, sono molto più brevi, con il recupero/decodifica dell'immagine e l'estrazione dei metadati che avvengono interamente su un thread di worker web. L'unico lavoro del thread principale prevede il passaggio dei dati da e verso il worker web.
Attività del thread principale nell'app di estrazione di metadati delle immagini. Tieni presente che in un thread di lavoro web aggiuntivo in cui viene svolta la maggior parte del lavoro.

Questa è la potenza di un lavoratore web. Invece di fare tutto sulla base il thread, tutto tranne il completamento del visualizzatore metadati con HTML viene eseguito thread separato. Ciò significa che il thread principale viene liberato per poter svolgere altre attività.

Forse il vantaggio più grande è che, a differenza della versione di questa app che non utilizza un web worker, lo script exif-reader non viene caricato ma sul thread dei worker web. Ciò significa che il costo il download, l'analisi e la compilazione dello script exif-reader avvengono in base al thread principale.

Adesso analizziamo il codice dei worker web che rende possibile tutto questo.

Uno sguardo al codice worker web

Non basta vedere la differenza che fa un web worker, è utile anche per almeno in questo caso, l'aspetto del codice, in modo da sapere possibile nell'ambito dei worker web.

Inizia con il codice del thread principale che deve verificarsi prima che il worker web possa inserisci l'immagine:

// scripts.js

// Register the Exif reader web worker:
const exifWorker = new Worker('/js/with-worker/exif-worker.js');

// We have to send image requests through this proxy due to CORS limitations:
const imageFetchPrefix = 'https://res.cloudinary.com/demo/image/fetch/';

// Necessary elements we need to select:
const imageFetchPanel = document.getElementById('image-fetch');
const imageExifDataPanel = document.getElementById('image-exif-data');
const exifDataPanel = document.getElementById('exif-data');
const imageInput = document.getElementById('image-url');

// What to do when the form is submitted.
document.getElementById('image-form').addEventListener('submit', event => {
  // Don't let the form submit by default:
  event.preventDefault();

  // Send the image URL to the web worker on submit:
  exifWorker.postMessage(`${imageFetchPrefix}${imageInput.value}`);
});

// This listens for the Exif metadata to come back from the web worker:
exifWorker.addEventListener('message', ({ data }) => {
  // This populates the Exif metadata viewer:
  exifDataPanel.innerHTML = data.message;
  imageFetchPanel.style.display = 'none';
  imageExifDataPanel.style.display = 'block';
});

Questo codice viene eseguito sul thread principale e configura il modulo per l'invio dell'URL dell'immagine a cui il worker web. Da qui, il codice del worker web inizia con importScripts che carica lo script exif-reader esterno e quindi imposta la classe pipeline di messaggistica al thread principale:

// exif-worker.js

// Import the exif-reader script:
importScripts('/js/with-worker/exifreader.js');

// Set up a messaging pipeline to send the Exif data to the `window`:
self.addEventListener('message', ({ data }) => {
  getExifDataFromImage(data).then(status => {
    self.postMessage(status);
  });
});

Questo bit di JavaScript configura la pipeline di messaggistica in modo che, quando l'utente invia il modulo con un URL a un file JPEG, l'URL arriva nel worker web. Da qui, il bit di codice successivo estrae i metadati EXIF dal file JPEG, crea una stringa HTML e la invia nuovamente all'elemento window per essere mostrati all'utente:

// Takes a blob to transform the image data into an `ArrayBuffer`:
// NOTE: these promises are simplified for readability, and don't include
// rejections on failures. Check out the complete web worker code:
// https://glitch.com/edit/#!/exif-worker?path=js%2Fwith-worker%2Fexif-worker.js%3A10%3A5
const readBlobAsArrayBuffer = blob => new Promise(resolve => {
  const reader = new FileReader();

  reader.onload = () => {
    resolve(reader.result);
  };

  reader.readAsArrayBuffer(blob);
});

// Takes the Exif metadata and converts it to a markup string to
// display in the Exif metadata viewer in the DOM:
const exifToMarkup = exif => Object.entries(exif).map(([exifNode, exifData]) => {
  return `
    <details>
      <summary>
        <h2>${exifNode}</h2>
      </summary>
      <p>${exifNode === 'base64' ? `<img src="data:image/jpeg;base64,${exifData}">` : typeof exifData.value === 'undefined' ? exifData : exifData.description || exifData.value}</p>
    </details>
  `;
}).join('');

// Fetches a partial image and gets its Exif data
const getExifDataFromImage = imageUrl => new Promise(resolve => {
  fetch(imageUrl, {
    headers: {
      // Use a range request to only download the first 64 KiB of an image.
      // This ensures bandwidth isn't wasted by downloading what may be a huge
      // JPEG file when all that's needed is the metadata.
      'Range': `bytes=0-${2 ** 10 * 64}`
    }
  }).then(response => {
    if (response.ok) {
      return response.clone().blob();
    }
  }).then(responseBlob => {
    readBlobAsArrayBuffer(responseBlob).then(arrayBuffer => {
      const tags = ExifReader.load(arrayBuffer, {
        expanded: true
      });

      resolve({
        status: true,
        message: Object.values(tags).map(tag => exifToMarkup(tag)).join('')
      });
    });
  });
});

Niente da leggere, ma si tratta anche di un caso d'uso piuttosto complesso per i lavoratori web. Tuttavia, i risultati valgono il lavoro e non si limitano a questo caso d'uso. Puoi utilizzare i web worker per qualsiasi cosa, ad esempio per isolare le chiamate a fetch ed elaborando le risposte, elaborando grandi quantità di dati senza bloccare thread principale, ed è solo per i principianti.

Quando migliori le prestazioni delle tue applicazioni web, inizia a pensare a tutto ciò che può essere ragionevolmente fatto in un contesto di worker web. I guadagni potrebbero essere significativi e possono migliorare complessivamente l'esperienza utente sul tuo sito web.