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

Lazy loading per i video

Includere video all'interno di pagine web è sempre più frequente: ecco come implementarne il lazy loading con JavaScript.
Includere video all'interno di pagine web è sempre più frequente: ecco come implementarne il lazy loading con JavaScript.
Link copiato negli appunti

Pensando alla maggior parte dei siti web moderni, soprattutto quelli basati su

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

come

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

, è facile convincersi che molti di essi utilizzano un layout abbastanza simile, quasi uno standard de facto. C'è un'immagine o uno slider in alto che identifica il brand o ne mostra i principali prodotti, seguito poi da sezioni più o meno variabili. In alcuni casi, però, tale slider è sostituito da un video, che può rendere più accattivante l'aspetto del sito. E non mancano soluzioni non convenzionali (come

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

), che sfruttano i video addirittura come sfondo full screen.

Eppure, la scelta di includere video su siti web moderni potrebbe sembrare un po' azzardata, soprattutto se non si provvede opportunamente alla gestione del loro caricamento, e del conseguente impatto sulla banda. Un video, infatti, è in genere molto pesante (soprattutto se la sua qualità è elevata), e non è particolarmente adatto a tutti i contesti, soprattutto nei casi in cui la banda a disposizione del browser è molto limitata.

In questa lezione mostreremo come implementare un meccanismo per il lazy loading di un video. La soluzione che discuteremo sarà basata su quella proposta dallo sviluppatore Ben Robertson,

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

. In breve, la soluzione consisterà nel caricare i video specificati all'interno degli elementi <source> sfruttando

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

e qualche accorgimento non banale. A ciò seguirà un sapiente uso delle

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

, in combinazione con l'evento canplaythrough.

Il codice HTML

Cominciamo subito dando uno sguardo al codice

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

:

<video class="js-video-loader" poster="images/poster.jpg" muted="true" loop="true">
  <source data-src="videos/video.webm" type="video/webm">
  <source data-src="videos/video.mp4" type="video/mp4">
</video>

La prima cosa da notare è il fatto che tutti i tag <source> non hanno alcun attributo src: i path dei due video, infatti, sono assegnati agli attributi data-src. Questa scelta evita che il browser carichi automaticamente i video, permettendoci di posticiparne il caricamento e renderlo programmatico sfruttando JavaScript. L'unica cosa ad essere effettivamente caricata è l'immagine specificata dall'attributo poster.

Il codice JavaScript

A questo punto, faremo riferimento alla classe JavaScript menzionata all'inizio di questa lezione. Diamo uno sguardo al costruttore:

constructor () {
  this.videos = Array.from(document.querySelectorAll('video.js-video-loader')); 

  if (typeof Promise === 'undefined'
      || !this.videos
      || window.matchMedia('(prefers-reduced-motion)').matches
      || window.innerWidth < 992
  ) {
    return;
  }
  this.videos.forEach(this.loadVideo.bind(this));
}

Questo costruttore non fa altro che selezionare tutti i video con classe js-video-loader, ed eseguire il metodo loadVideo su ognuno di essi. Tutto ciò a meno che:

  • non siano supportate le promise
  • nessun video della pagina ha classe js-video-loader
  • nel caso la proprietà
    [!] Ci sono problemi con l'autore. Controllare il mapping sull'Author Manager

    prefers-reduced-motion sia impostata su reduce

  • lo schermo sia piccolo (quest'ultima possibilità, così come la precedente, potrebbe tranquillamente essere omessa; qui è mantenuta, di fatto, per disabilitare il lazy loading per gli schermi più piccoli)

A questo punto, diamo un'occhiata al metodo loadVideo():

loadVideo(video) {
  this.setSource(video);
  video.load();
  this.checkLoadTime(video);
}

Di questo metodo, la parte più interessante è la prima riga, quella che esegue setSource. Vediamone il codice:

setSource (video) {
  let children = Array.from(video.children);
  children.forEach(child => {
    if ( child.tagName === 'SOURCE'
         && typeof child.dataset.src !== 'undefined' ) {
       child.setAttribute('src', child.dataset.src);
    }
  });
}

In pratica, non facciamo altro che assegnare ad ogni tag <source> di ogni video, un nuovo attributo src con il path specificato inizialmente su data-src. A seguito di ciò, l'esecuzione di video.load() in loadVideo avvia il caricamento vero e proprio.

La porzione di codice forse più interessante si trova però nella definizione del metodo checkLoadTime():

checkLoadTime(video) {
    // Creiamo la prima promise, che si risolve
    // in corrispondenza dell'evento video.canplaythrough
    const videoLoad = new Promise((resolve) => {
      video.addEventListener('canplaythrough', () => {
        resolve('can play');
      });
    });
    // Creiamo la seconda promise, che si risolve
    // dopo un tempo predefinito (2 secondi)
    const videoTimeout = new Promise((resolve) => {
      setTimeout(() => {
        resolve('The video timed out.');
      }, 2000);
    });

    // Sfruttiamo il metodo race
    Promise.race([videoLoad, videoTimeout]).then((data) => {
      if (data === 'can play') {
        video.play();
        setTimeout(() => {
          video.classList.add('video-loaded');
        }, 500);
      }
      else {
        this.cancelLoad(video);
      }
    });
 }

Vengono create due promise. La prima è risolta quando viene generato l'evento canplaythrough <video> setTimeout race .then() can play video.play()

Il metodo cancelLoad (l'ultimo che rimane da analizzare) fa in pratica l'opposto di quanto visto con loadVideo, rimuovendo i path dei video dagli attributi src, ed eseguendo nuovamente video.load() per resettare l'elemento:

cancelLoad (video) {
  let children = Array.from(video.children);
  children.forEach(child => {
    if ( child.tagName === 'SOURCE'
         && typeof child.dataset.src !== 'undefined' ) {
      child.parentNode.removeChild(child);
    }
  });
  // Ricarico il video senza source, per resettarlo
  video.load();
}

Conclusioni

La soluzione proposta non risolve tutti i problemi, in quanto una connessione limitata impedirebbe comunque il caricamento dell'intero video. Tuttavia, ciò significa anche che probabilmente la disponibilità di banda non è adeguata alla riproduzione di un video di grandi dimensioni, e probabilmente è meglio risparmiare la connessione per caricare altri contenuti.

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