{"id":815,"date":"2018-05-22T10:43:13","date_gmt":"2018-05-22T08:43:13","guid":{"rendered":"https:\/\/alistapart.com\/it\/article\/2018-05-22-08-45-33\/"},"modified":"2018-05-22T10:43:13","modified_gmt":"2018-05-22T08:43:13","slug":"2018-05-22-08-45-33","status":"publish","type":"article","link":"https:\/\/alistapart.com\/it\/article\/2018-05-22-08-45-33\/","title":{"rendered":"La miglior richiesta \u00e8 nessuna richiesta. Revisione"},"content":{"rendered":"<p>Nel corso degli ultimi dieci anni, l&#8217;ottimizzazione della performance web \u00e8 stata controllata da una linea guida indiscutibile: la miglior richiesta \u00e8 nessuna richiesta. Una regola molto semplice, facile da interpretare: l&#8217;eliminazione di ogni chiamata di rete per una risorsa migliora la performance. Ogni attributo <code>src<\/code> risparmiato, ogni elemento <code>link<\/code> eliminato. Ma tutto \u00e8 cambiato ora che <a href=\"https:\/\/www.smashingmagazine.com\/2016\/02\/getting-ready-for-http2\/#http2\" rel=\"noopener\">abbiamo a disposizione HTTP\/2<\/a>, vero? Progettato per il web moderno, HTTP\/2 \u00e8 pi\u00f9 efficiente nel rispondere a un gran numero di richieste rispetto al suo predecessore. Quindi la domanda \u00e8: vale ancora la vecchia regola del ridurre le request?<\/p>\n<div class=\"paragrafo\">\n<h2 id=\"section1\">Cosa \u00e8 cambiato con HTTP\/2?<\/h2>\n<p>Per capire in che modo HTTP\/2 sia diverso, ci \u00e8 utile conoscere i suoi predecessori. Eccone una breve storia. HTTP \u00e8 costruito su TCP. Mentre TCP \u00e8 potente ed \u00e8 in grado di trasferire molti dati in maniera affidabile, il modo in cui HTTP\/1 utilizzava TCP era inefficiente. Ogni risorsa richiesta richiedeva una nuova connessione TCP. E ogni connessione TCP richiedeva la sincronizzazione tra il client e il server, risultando in un ritardo iniziale mentre il browser stabiliva una connessione. Questo andava bene nel momento in cui la maggioranza dei contenuti dei siti web consisteva di documenti senza stili che non caricavano risorse aggiuntive, come le immagini o i file JavaScript.<\/p>\n<p>Gli aggiornamenti in HTTP\/1.1 hanno cercato di superare questi limiti. I client erano in grado di usare una connessione TCP per risorse multiple, ma dovevano ancora scaricarle in sequenza. La cosiddetta \u201chead of line blocking\u201d fa apparire i grafici a cascata esattamente come delle cascate:<\/p>\n<div id=\"figure1\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-1.png\" border=\"0\" alt=\"Figura 1. Schema a cascata di risorse che si caricano su una connessione TCP pipelined\" width=\"100%\" \/><\/p>\n<p>Figura 1. Schema a cascata di risorse che si caricano su una connessione TCP pipelined<\/p>\n<\/div>\n<p>Inoltre, la maggior parte dei browser ha cominciato ad aprire connessioni TCP multiple in parallelo, limitate a un numero piuttosto basso per dominio. Anche con tali ottimizzazioni, HTTP\/1.1 non \u00e8 adatto al numero considerevole di risorse degli odierni siti web. Da qui il detto \u201cla miglior richiesta \u00e8 nessuna richiesta\u201d. Le connessioni TCP sono costose e richiedono tempo. Questo \u00e8 il motivo per cui usiamo cose come la concatenazione, le image sprite e l&#8217;inlining delle risorse: per evitare nuove connessioni e riutilizzare quelle esistenti.<\/p>\n<p>HTTP\/2 \u00e8 fondamentalmente diverso da HTTP\/1.1. HTTP\/2 usa una singola connessione TCP e permette a pi\u00f9 risorse di essere scaricate in parallelo rispetto ai suoi predecessori. Pensate a questa singola connessione TCP come a un tunnel largo in cui i dati vengono inviati in <a href=\"https:\/\/hpbn.co\/http2\/#streams-messages-and-frames\" rel=\"noopener\">frame<\/a>. Sul client, tutti i pacchetti vengono riassemblati nel loro sorgente originale. Usando una paio di elementi <code>link<\/code> per trasferire i fogli di stile \u00e8 ora praticamente tanto efficiente quanto tutti i vostri fogli di stile in un unico file.<\/p>\n<div id=\"figure2\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-2.png\" border=\"0\" alt=\"Figura 2. Schema a cascata di risorse che si caricano su una connessione TCP condivisa\" width=\"100%\" \/><\/p>\n<p>Figura 2. Schema a cascata di asset che si caricano su una connessione TCP condivisa<\/p>\n<\/div>\n<p>Tutte le connessioni usano lo stesso stream, quindi condividono anche la banda. A seconda del numero di risorse, questo potrebbe significare che le risorse individuali potrebbero metterci di pi\u00f9 ad essere trasmesse al lato client su connessioni con poca banda.<\/p>\n<p>Ci\u00f2 significa anche che l&#8217;assegnazione delle priorit\u00e0 alle risorse non \u00e8 fatta cos\u00ec facilmente come con HTTP\/1.1: l&#8217;ordine delle risorse nel documento ha un impatto sull&#8217;ordine di download. Con HTTP\/2, tutto accade allo stesso tempo! <a href=\"https:\/\/http2.github.io\/http2-spec\/#StreamPriority\" rel=\"noopener\">La specifica di HTTP\/2 contiene informazioni sull&#8217;assegnazione di priorit\u00e0 allo stream<\/a>, ma nel momento in cui scrivo, fa ancora parte di un futuro remoto il mettere nelle mani degli sviluppatori il controllo sull&#8217;assegnazione di priorit\u00e0.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2 id=\"section2\">La miglior richiesta \u00e8 nessuna richiesta: scegliere selettivamente<\/h2>\n<p>Allora, cosa possiamo fare per superare la mancanza di priorit\u00e0 delle risorse a cascata? Cosa ne dite del non sprecare banda? Pensate ancora alla prima regola dell&#8217;ottimizzazione della performance: la miglior richiesta \u00e8 nessuna richiesta. Reinterpretiamo questa regola.<\/p>\n<p>Per esempio, consideriamo una tipica pagina web (in questo caso, da Dynatrace). Lo screenshot qui sotto mostra un pezzo di documentazione online consistente di diversi componenti: la navigazione principale, un footer, dei breadcrumb, una sidebar e l&#8217;articolo principale.<\/p>\n<div id=\"figure3\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-3.png\" border=\"0\" alt=\"Figura 3. Un tipico sito web scomposto in alcune sue componenti\" width=\"100%\" \/><\/p>\n<p>Figura 3. Un tipico sito web scomposto in alcune sue componenti<\/p>\n<\/div>\n<p>Su altre pagine dello stesso sito abbiamo cose come una testata, i social media outlet, le gallery o altre componenti. Ciascuna delle quali \u00e8 definita dal suo markup e dal suo foglio di stile.<\/p>\n<p>Negli ambienti HTTP\/1.1, combineremmo tipicamente tutti i fogli di stile delle componenti in un unico file CSS. La miglior richiesta \u00e8 nessuna richiesta: una connessione TCP per trasferire tutto il CSS necessario, anche per le pagine che l&#8217;utente non ha ancora visto. Questo pu\u00f2 risultare in un enorme file CSS.<\/p>\n<p>Il problema \u00e8 aggravato quando un sito usa una libreria come Bootstrap, che ha raggiunto la soglia dei 300 kB, aggiungendo a questa del CSS specifico per il sito. La quantit\u00e0 <em>effettiva<\/em> di CSS richiesto da ogni pagina, in alcuni casi, era addirittura <a href=\"https:\/\/twitter.com\/dalmaer\/status\/377157438778376192\" rel=\"noopener\">meno del 10%<\/a> della quantit\u00e0 caricata:<\/p>\n<div id=\"figure4\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-4.png\" border=\"0\" alt=\"Figura 4. Copertura del codice di una pagina web di cinema a caso che usa il 10% del totale di 300 kB di CSS. Quasta pagina \u00e8 costruita su Bootstrap.\" width=\"100%\" \/><\/p>\n<p>Figura 4. Copertura del codice di una pagina web di cinema a caso che usa il 10% del totale di 300 kB di CSS. Questa pagina \u00e8 costruita su Bootstrap.<\/p>\n<\/div>\n<p>Ci sono addirittura tool come <a href=\"https:\/\/github.com\/giakki\/uncss\" rel=\"noopener\">UnCSS<\/a> che hanno lo scopo di eliminare gli stili inutilizzati.<\/p>\n<p>L&#8217;esempio della documentazione di Dynatrace mostrato in figura 3 \u00e8 costruito con <a href=\"http:\/\/groundhog.dynalabs.io\/\" rel=\"noopener\">la libreria di stili propria dell&#8217;azienda<\/a>, creata su misura per i bisogni specifici del sito, invece che con Bootstrap, che \u00e8 una soluzione general purpose. Tutti i componenti nella style library dell&#8217;azienda sommati arrivano a 80 kB di CSS. Il CSS effettivamente usato sulla pagina \u00e8 diviso tra otto di quei componenti, per un totale di 8.1 kB. Quindi, anche se la libreria \u00e8 su misura per gli specifici bisogni del sito, la pagina usa ancora solo circa il 10% del CSS che scarica.<\/p>\n<p>HTTP\/2 ci permette di essere molto pi\u00f9 esigenti in termini di file che vogliamo trasmettere. La richiesta stessa non \u00e8 cos\u00ec costosa come lo \u00e8 in HTTP\/1.1, quindi possiamo tranquillamente usare pi\u00f9 elementi <code>link<\/code>, puntando direttamente agli elementi usati in quella particolare pagina:<\/p>\n<pre id=\"snippet1\" class=\" language-markup\"><code class=\" language-markup\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/base.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/typography.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/layout.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/navbar.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/article.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/footer.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/sidebar.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/breadcrumbs.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/pre>\n<p>\u00a0<\/p>\n<p>Questo, ovviamente, vale anche per ogni sprite map o JavaScript bundle. Trasferendo solo quello di cui si ha effettivamente bisogno, la quantit\u00e0 di dati trasferiti dal vostro sito pu\u00f2 essere ridotta enormemente! Confrontate i tempi di download per bundle e file singolo mostrati con i tempi di Chrome qui sotto:<\/p>\n<div id=\"figure5\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-5.png\" border=\"0\" alt=\"Figura 5. Download del bundle. Dopo che \u00e8 stata stabilita la connessione iniziale, il bundle ci impiega 583 ms per il download su una rete 3G regolare.\" width=\"100%\" \/><\/p>\n<p>Figura 5. Download del bundle. Dopo che \u00e8 stata stabilita la connessione iniziale, il bundle ci impiega 583 ms per il download su una rete 3G regolare.<\/p>\n<\/div>\n<div id=\"figure6\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-6.png\" border=\"0\" alt=\"Figura 6. Suddividete solo i file necessari e scaricateli in parallelo. La connessione iniziale ci mette pi\u00f9 o meno lo stesso tempo, ma il contenuto (un foglio di stile, in questo caso) si scarica molto pi\u00f9 rapidamente perch\u00e9 \u00e8 pi\u00f9 piccolo.\" width=\"100%\" \/><\/p>\n<p>Figura 6. Suddividete solo i file necessari e scaricateli in parallelo. La connessione iniziale ci mette pi\u00f9 o meno lo stesso tempo, ma il contenuto (un foglio di stile, in questo caso) si scarica molto pi\u00f9 rapidamente perch\u00e9 \u00e8 pi\u00f9 piccolo.<\/p>\n<\/div>\n<p>La prima immagine mostra che, incluso il tempo richiesto dal browser per stabilire la connessione iniziale, il bundle ha bisogno di circa 700 ms per il download su una connessione 3G regolare. La seconda immagine mostra i valori della tempistica per un file CSS su otto che compongono la pagina. L&#8217;inizio della response (TTFB) impiega altrettanto, ma dal momento che il file \u00e8 molto pi\u00f9 piccolo (meno di 1 kB), il contenuto \u00e8 scaricato quasi immediatamente.<\/p>\n<p>Questo potrebbe non sembrare impressionante quando si osserva un&#8217;unica risorsa, ma, come mostrato sotto, dal momento che tutti e otto i fogli di stile sono scaricati in parallelo, possiamo ancora risparmiare molto transfer time quando lo confrontiamo con l&#8217;approccio bundle.<\/p>\n<div id=\"figure7\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-7.png\" border=\"0\" alt=\"Figura 7. Tutti i fogli di stile sul variante suddiviso si caricano in parallelo.\" width=\"100%\" \/><\/p>\n<p>Figura 7. Tutti i fogli di stile sul variante suddiviso si caricano in parallelo.<\/p>\n<\/div>\n<p>Si pu\u00f2 vedere un pattern simile quando si fa passare la stessa pagina per <a href=\"https:\/\/www.webpagetest.org\/\" rel=\"noopener\">webpagetest.org<\/a> su regolare 3G. Il bundle completo (<code>main.css<\/code>) comincia a scaricarsi appena dopo 1.5 s (linea gialla) e impiega 1.3 secondi a fare il download; il <a href=\"http:\/\/bit.ly\/ttfmp-doc\" rel=\"noopener\">time to first meaningful paint<\/a> \u00e8 di circa 3.5 secondi (linea verde):<\/p>\n<div id=\"figure8\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-8.png\" border=\"0\" alt=\"Figura 8. Download di tutta la pagina del bundle, 3G regolare.\" width=\"100%\" \/><\/p>\n<p>Figura 8. Download di tutta la pagina del bundle, 3G regolare.<\/p>\n<\/div>\n<p>Quando suddividiamo il bundle CSS, ogni foglio di stile comincia il download a 1.5s (linea gialla) e impiega 315-375ms per finire. Come risultato, possiamo ridurre il time to first meaningful paint di pi\u00f9 di un secondo (linea verde):<\/p>\n<div id=\"figure9\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-9.png\" border=\"0\" alt=\"Figura 9. Download di file singoli, 3G regolare.\" width=\"100%\" \/><\/p>\n<p>Figura 9. Download di file singoli, 3G regolare.<\/p>\n<\/div>\n<p>Secondo le nostre misurazioni, la differenza tra i file in bundle e quelli suddivisi ha un impatto maggiore sul 3G lento rispetto al 3G normale. Su quest&#8217;ultimo, il bundle necessita di un totale di 4,5s per essere scaricato, risultando in un time to first meaningful paint attorno ai 7s:<\/p>\n<div id=\"figure10\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-10.png\" border=\"0\" alt=\"Figura 10. Bundle, 3G lento.\" width=\"100%\" \/><\/p>\n<p>Figura 10. Bundle, 3G lento.<\/p>\n<\/div>\n<p>La stessa pagina con file divisi su connessioni 3G lente tramite webpagetest.org produce un meaningful paint (linea verde) che si verifica 4s prima:<\/p>\n<div id=\"figure11\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-11.png\" border=\"0\" alt=\"Figura 11. File suddivisi, 3G lento.\" width=\"100%\" \/><\/p>\n<p>Figura 11. File suddivisi, 3G lento.<\/p>\n<\/div>\n<p>La cosa interessante \u00e8 che ci\u00f2 che \u00e8 era considerato un anti-pattern delle prestazioni in HTTP\/1.1 &#8211; utilizzare molti riferimenti alle risorse &#8211; diventa una best practice nell&#8217;era HTTP\/2. Inoltre, la regola rimane la stessa! Il significato cambia leggermente.<\/p>\n<p>La miglior richiesta \u00e8 nessuna richiesta: lasciate perdere i file e il codice che non serve ai vostri utenti!<\/p>\n<p>Va notato che il successo di questo approccio \u00e8 fortemente legato al numero di risorse trasferite. L&#8217;esempio precedente utilizzava il 10% della libreria di fogli di stile originale, che comporta un&#8217;enorme riduzione delle dimensioni del file. Il download dell&#8217;intera libreria dell&#8217;interfaccia utente in file divisi potrebbe dare risultati diversi. Per esempio, <a href=\"http:\/\/engineering.khanacademy.org\/posts\/js-packaging-http2.htm\" rel=\"noopener\">Khan Academy<\/a> ha scoperto che suddividendo i loro bundle JavaScript, la dimensione totale dell&#8217;applicazione &#8211; e pertanto il transfer time &#8211; \u00e8 peggiorato drasticamente. Ci\u00f2 \u00e8 dovuto principalmente a due motivi: un&#8217;enorme quantit\u00e0 di file JavaScript (circa 100) e i poteri spesso sottostimati di Gzip.<\/p>\n<p>Gzip (ma anche Brotli) produce rapporti di compressione pi\u00f9 elevati quando c&#8217;\u00e8 una ripetizione nei dati che sta comprimendo. Ci\u00f2 significa che un pacchetto compresso con Gzip ha un ingombro molto inferiore rispetto ai singoli file con Gzip. Pertanto, se si intende scaricare un intero insieme di file, il rapporto di compressione delle risorse in bundle potrebbe superare quello dei singoli file scaricati in parallelo. Testate di conseguenza.<\/p>\n<p>Inoltre, siate consci della vostra user base. Sebbene HTTP\/2 sia stato <a href=\"https:\/\/caniuse.com\/#feat=http2\" rel=\"noopener\">ampiamente adottato<\/a>, alcuni dei vostri utenti potrebbero essere limitati alle connessioni HTTP\/1.1. Questi soffriranno per via delle risorse suddivise.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2 id=\"section3\">La miglior richiesta \u00e8 nessuna richiesta: caching e versioning<\/h2>\n<p>A questo punto, abbiamo visto con il nostro esempio come ottimizzare la prima visita a una pagina. Il bundle viene diviso in file separati e il client riceve solo ci\u00f2 di cui ha bisogno per essere visualizzato su una pagina. Questo ci d\u00e0 la possibilit\u00e0 di esaminare qualcosa che si tende a trascurare quando ottimizzano le prestazioni: le visite successive.<\/p>\n<p>Nelle visite successive vogliamo evitare di ritrasferire degli asset inutilmente. Gli header HTTP come <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Cache-Control\" rel=\"noopener\">Cache-Control<\/a> (e la loro implementazione nei server come <a href=\"https:\/\/www.askapache.com\/htaccess\/apache-speed-cache-control\/\" rel=\"noopener\">Apache<\/a> e <a href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_headers_module.html\" rel=\"noopener\">NGINX<\/a>) ci permette di memorizzare file sul disco dell&#8217;utente per un certo periodo di tempo. Alcuni server CDN hanno come default alcuni minuti. Altri alcune ore o addirittura giorni. L&#8217;idea \u00e8 che durante una sessione, gli utenti non dovrebbero scaricare quello che hanno gi\u00e0 scaricato in passato (a meno che non abbiano pulito la propria cache nel frattempo). Per esempio, la seguente header directive di Cache-Control ci garantisce che il file sia memorizzato in qualsiasi cache disponibile, per 600 secondi.<\/p>\n<pre id=\"snippet2\"><code>Cache-Control: public, max-age=600<\/code><\/pre>\n<p>\u00a0<\/p>\n<p>Possiamo usare Cache-Control a nostro vantaggio perch\u00e9 sia molto pi\u00f9 stringente. Nella nostra prima ottimizzazione abbiamo deciso di scegliere selettivamente le risorse ed essere schizzinosi riguardo a quello che trasferiamo al client, quindi memorizziamo queste risorse sulla macchina per un periodo di tempo lungo:<\/p>\n<pre id=\"snippet3\"><code>Cache-Control: public, max-age=31536000<\/code><\/pre>\n<p>\u00a0<\/p>\n<p>Il numero di cui sopra \u00e8 un anno in secondi. L&#8217;utilit\u00e0 di impostare a una valore alto il <code>max-age<\/code> di Cache-Control \u00e8 che l&#8217;asset sar\u00e0 memorizzato dal client per un periodo di tempo lungo. Lo screenshot seguente mostra un grafico a cascata della prima visita. Ogni asset nel file HTML \u00e8 richiesto:<\/p>\n<div id=\"figure12\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-12.png\" border=\"0\" alt=\"Figura 12. Prima visita: ogni asset \u00e8 richiesto.\" width=\"100%\" \/><\/p>\n<p>Figura 12. Prima visita: ogni asset \u00e8 richiesto.<\/p>\n<\/div>\n<p>Con gli header di Cache-Control impostati appropriatamente, una visita seguente risulter\u00e0 in meno richieste. Lo screenshot sottostante mostra che tutti gli asset richiesti sul nostro dominio di test non fanno scattare alcuna richiesta. Gli asset da un altro dominio con gli header di Cache-Control impostate in maniera impropria fanno ancora scattare una singola richiesta, cos\u00ec come fanno le risorse che non sono state trovate:<\/p>\n<div id=\"figure13\" class=\"image full\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2018\/05\/figure-13.png\" border=\"0\" alt=\"Figura 13. Seconda visita: vengono richiesti di nuovo solo alcuni SVG messi malamente in cache da un server differente.\" width=\"100%\" \/><\/p>\n<p>Figura 13. Seconda visita: vengono richiesti di nuovo solo alcuni SVG messi malamente in cache da un server differente.<\/p>\n<\/div>\n<p>Quando si tratta di invalidare un asset in cache (il che, di conseguenza, \u00e8 una <a href=\"https:\/\/martinfowler.com\/bliki\/TwoHardThings.html\" rel=\"noopener\">delle due cose pi\u00f9 difficili in informatica<\/a>), usiamo semplicemente un nuovo asset. Vediamo come funzionerebbe con il nostro esempio. <a href=\"https:\/\/css-tricks.com\/strategies-for-cache-busting-css\/#article-header-id-2\" rel=\"noopener\">Il caching funziona basandosi sui nomi di file<\/a>. Un nuovo nome di file pu\u00f2 far scattare un nuovo download. Precedentemente, abbiamo suddiviso la nostra code base in pezzi ragionevoli. Un version indicator ci assicura che ogni nome di file rimane unico:<\/p>\n<pre id=\"snippet4\" class=\" language-markup\"><code class=\" language-markup\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/header.v1.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/article.v1.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/pre>\n<p>\u00a0<\/p>\n<p>Dopo una modifica ai nostri stili dell&#8217;articolo, dovremmo modificare il numero di versione:<\/p>\n<pre id=\"snippet5\" class=\" language-markup\"><code class=\" language-markup\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/header.v1.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>link<\/span> <span class=\"token attr-name\">rel<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>stylesheet<span class=\"token punctuation\">\"<\/span><\/span> <span class=\"token attr-name\">href<\/span><span class=\"token attr-value\"><span class=\"token punctuation\">=<\/span><span class=\"token punctuation\">\"<\/span>\/css\/article.v2.css<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/pre>\n<p>\u00a0<\/p>\n<p>Un&#8217;alternativa al tenere traccia della versione del file \u00e8 di impostare <a href=\"https:\/\/github.com\/sindresorhus\/rev-hash\" rel=\"noopener\">un revision hash basato sul contenuto del file<\/a> con dei tool di automazione.<\/p>\n<p>Va bene memorizzare i propri asset sul client per un periodo di tempo. Tuttavia, il vostro HTML dovrebbe essere pi\u00f9 transitorio nella maggior parte dei casi. Tipicamente, il file HTML contiene le informazioni su quali risorse scaricare. Se voleste che le vostre risorse cambino (come caricare article.v2.css invece di article.v1.css, come abbiamo appena visto), dovrete aggiornare i riferimenti ad essi nel vostro HTML. I server CDN popolari mettono in cache HTML per non pi\u00f9 di sei minuti, ma potete decidere cosa va meglio per la vostra applicazione.<\/p>\n<p>Di nuovo, la miglior richiesta \u00e8 nessuna richiesta: memorizzate i file sul client per quanto pi\u00f9 tempo possibile e non richiedeteli di nuovo. Le edizioni recenti di Firefox e Edge hanno addirittura <a href=\"https:\/\/developer.mozilla.org\/de\/docs\/Web\/HTTP\/Headers\/Cache-Control#Revalidation_and_reloading\" rel=\"noopener\">una direttiva immutabile per Cache-Control<\/a>, che prende di mira proprio questo pattern.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2 id=\"section4\">Conclusioni<\/h2>\n<p>HTTP\/2 \u00e8 stato progettato da zero per gestire le inefficienze di HTTP\/1. Innescare un gran numero di richieste in un ambiente HTTP\/2 non \u00e8 intrinsecamente pi\u00f9 negativo per la performance, ma trasferire dati non necessari lo \u00e8.<\/p>\n<p>Per raggiungere il pieno potenziale di HTTP\/2, dobbiamo osservare ogni caso individualmente. Un&#8217;ottimizzazione che potrebbe andar bene per un sito web potrebbe avere un effetto negativo su un altro. Con tutti i benefici che derivano da HTTP\/2, la regola d&#8217;oro dell&#8217;ottimizzazione della performance si applica ancora: la miglior richiesta \u00e8 nessuna richiesta. Solo che questa volta diamo un&#8217;occhiata alla quantit\u00e0 effettiva di dati trasferiti.<\/p>\n<p>Trasferite solo quello che effettivamente serve ai vostri utenti. Niente di pi\u00f9, niente di meno.<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Ora che HTTP\/2 gode di maggior ubiquit\u00e0, \u00e8 particolarmente importante sfidare quella che una volta era l&#8217;indiscutibile regola del resource bundling nella performance del client site. Seguiamo Stefan Baumgartner mentre ci guida attraverso le potenziali trappole e gli esiti negativi del bundling negli ambienti HTTP\/2.<\/p>\n","protected":false},"author":818,"featured_media":7000838,"comment_status":"open","ping_status":"open","template":"","categories":[242,270,213],"tags":[],"coauthors":[526],"class_list":["post-815","article","type-article","status-publish","has-post-thumbnail","hentry","category-browser","category-il-server-side","category-numero-236-30-novembre-2017"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article\/815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article"}],"about":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/types\/article"}],"author":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/users\/818"}],"replies":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/comments?post=815"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media\/7000838"}],"wp:attachment":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media?parent=815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/categories?post=815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/tags?post=815"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/coauthors?post=815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}