JavaScript is de grootste boosdoener bij trage websites
JavaScript is als zout in een maaltijd: het verrijkt de ervaring. Maar gooi je te veel zout door de maaltijd, dan verpest je de smaak. Net zo heeft het in één keer inladen van veel JavaScript een negatief effect op de snelheid van een website, en daarmee op de gebruikservaring.
In dit artikel over websiteperformance leggen we op een begrijpelijke manier uit hoe dit komt. Daarna delen we onze eigen ervaringen met het verbeteren van de snelheid rondom JavaScript.
Verwerking van JavaScript
Vooral bij mobiel gebruik is te veel JavaScript een nadeel. De gemiddelde smartphone heeft veel meer moeite met het verwerken hiervan dan een laptop of pc. En daardoor duurt het op een smartphone vaak langer voordat interactie op de pagina kan plaatsvinden.
Om JavaScript te verwerken moet een browser vier stappen doorlopen:
- Download
De browser moet het JavaScript-bestand eerst downloaden. Hoe lang dat duurt, is afhankelijk van de snelheid van de internetverbinding. Op een mobiel 3G- of 4G-netwerk duurt dit downloaden langer dan met een snelle wifi- of LAN-verbinding.
Wanneer een JavaScript-bestand eenmaal is gedownload, wordt het bestand opgeslagen in de browsercache. Bij volgende paginabezoeken hoeft de browser het dus niet opnieuw te downloaden. Dat maakt de snelheid van deze eerste stap niet minder belangrijk. De positie van een pagina in zoekmachines is namelijk deels afhankelijk van de snelheid van de site volgens Google PageSpeed Insights. En daarbij neemt Google altijd het eerste bezoek als uitgangspunt, wanneer de JavaScript dus nog moet worden gedownload. - Uitpakken
Om de grootte van JavaScript-bestanden te beperken, is het gebruikelijk om ze op de server in te pakken. De browser hoeft dan minder te downloaden. De bestanden zijn dan compressed. Het ingepakte bestand moet wel weer worden uitgepakt: decompressed. Dat doet de browser direct na het downloaden. Wat dit betreft, is JavaScript niet heel anders dan andere bestandstypen. Ook die moeten worden gedownload en uitgepakt. Het verschil zit ’m in de volgende twee stappen, die we hieronder beschrijven. Die activiteiten zijn uniek voor het verwerken van JavaScript en zorgen ervoor dat 100 kB uitgepakt JavaScript een grotere impact heeft dan bijvoorbeeld een afbeelding van 100 kB. - Parsing/compiling
Na het uitpakken van het bestand vertaalt de browser de JavaScript-code. Deze wordt geanalyseerd, opgeknipt in kleinere delen en zoveel mogelijk verwerkt tot computercode. Deze code kan sneller worden uitgevoerd dan het voor mensen leesbare JavaScript. Dit heet parsing en compiling. Het is een complex proces, dat veel vraagt van de computerprocessor (CPU).
En in die CPU zit ’m het verschil tussen de apparaten: laptops, pc’s en smartphones in het hoge segment hebben een krachtigere processor dan de gemiddelde smartphone. Die heeft zo’n twee tot vijf keer zoveel tijd nodig om de JavaScript-code te parsen en compilen als de snelste telefoon. Dat resulteert al snel in een laadtijd van meerdere seconden. Zie het onderstaande diagram uit 2017 ter illustratie. - Uitvoering
Na het parsen en compilen kan de JavaScript-code worden uitgevoerd op de pagina. Ook dit kost weer meer tijd op apparaten met een minder krachtige CPU.
Tijdens het uitvoeren van stap 3 en 4 is de browser niet in staat om andere dingen te doen op de zogenaamde main thread, als het ware de hoofdweg van de browser. Het uitvoeren van JavaScript blokkeert daardoor andere zaken. Vandaar ook dat op een pagina pas interactie mogelijk is nadat de JavaScript is verwerkt.
Waarom mobiel gebruik belangrijk is
Juist mobiel, waar het gebruik over het algemeen sneller en korter is dan op een desktop, moet een gebruiker dus langer wachten op het laden van de pagina. Daarom vluchten mobiele gebruikers voor een betere ervaring naar gesloten apps. Een slechte ontwikkeling als je het ons vraagt, omdat dit ingaat tegen het open en altijd beschikbare karakter van het web.
Van het mobiele gebruik vindt maar 10 tot 15 procent plaats in een browser. Op de desktop is dat maar liefst 50 procent (zie deze presentatie van Alex Russel op Fronteers 2019). Denk maar aan alle applicaties die je in de browser kunt gebruiken, zoals e-mail, social media, videoplatforms, tekstverwerking, chats en andere (werkgerelateerde) software. Op mobiel hebben webapplicaties deze sprong naar de browser nooit kunnen maken.
Omdat het verschil tussen mobiel en desktop zo groot is, neemt Google een gemiddelde smartphone als uitgangspunt bij het testen van de snelheid van een website. Daarbij is de kans groot dat een mobiele score van onder de 40 een negatieve invloed heeft op je positie in de zoekresultaten.
Onze ervaring met het beter inladen van JavaScript
Voor meerdere klanten zijn we aan de slag gegaan met het verbeteren van de snelheid van hun websites. Hieronder geven we een aantal voorbeelden van significante snelheidswinst door aanpassingen in JavaScript.
Onnodige JavaScript verwijderen
De meest logische eerste stap is om onnodig ingeladen JavaScript te verwijderen. Zo konden we bij een van onze klanten een oude JavaScript-library verwijderen die niet meer werd gebruikt. Dat was een snelle winst van zo’n 100 kB aan JavaScript, dat anders onnodig door de bovengenoemde verwerkingsstappen ging. Bij een andere klant werd maatwerkcode meegestuurd naar de browser voor twee widgets die niet meer in gebruik waren. Het verwijderen van deze widgetcode leverde tientallen kB’s winst op.
Ook kwamen we slordigheden bij het gebruik van de jQuery-library tegen. Dit is een set van standaardfunctionaliteiten die je kunt gebruiken in andere code om sneller te kunnen werken. Deze zelfde library werd bij een van onze klanten wel drie keer ingeladen. Dit was nooit eerder opgemerkt, omdat JavaScript hiervoor geen foutmelding geeft. Ook hier was dus eenvoudig winst te behalen.
Geen of kleinere variant JavaScript-library
Een JavaScript-library kan toegevoegde waarde hebben, maar heeft dat lang niet altijd. Soms is maar een deel van de library in gebruik. En tegenwoordig kun je vaak al zonder libraries en met weinig extra moeite hetzelfde resultaat behalen. Daarom is het zeker de overweging waard om je code te herschrijven en de library te verwijderen.
Kost herschrijven te veel werk? Dan kun je, als je library deze mogelijkheid ondersteunt, overwegen om alleen een deel van de libarry in te laden. Dat kan bijvoorbeeld met jQuery UI, een uitbreiding op de eerdergenoemde jQuery-library. Deze uitbreiding biedt de mogelijkheid om slechts een klein onderdeel te downloaden en te gebruiken. Dit konden we bij een van onze klanten toepassen en dat scheelde flink.
Lichtgewicht-libraries
Een andere optie is het gebruik van lichtgewicht-alternatieven voor libraries. Zo is er voor de jQuery-code het veel kleinere Zepto.js, met grotendeels dezelfde jQuery-functies. Deze library is vaak gemakkelijk in te zetten en neemt maar 26 kB in beslag, terwijl de jQuery-library maar liefst 86 kB inneemt.
Een ander voorbeeld is Preact, een lichtgewicht-versie van de React-library. Deze hebben we nu twee keer ingezet, beide keren met succes en vrijwel zonder iets aan de oorspronkelijke React-code te hoeven veranderen. Bij één klant leverde dit een verkleining op van 452 naar 292 kB (uitgepakt, zie stap 2 hierboven). Dat is veel winst in maar drie uur werk.
Zo min mogelijk blokkeren
Zoals hierboven beschreven blokkeert JavaScript tijdens de uitvoering andere zaken op de main thread van de browser. Daarom is het van belang dat de content al zoveel mogelijk is gestyled voordat de browser begint aan het verwerken van de JavaScript. Bij meerdere projecten konden we hiervoor grote verbeteringen doorvoeren door de JavaScript-bestanden niet-blokkerend in te laden. De beste manier is vaak door middel van een defer-attribuut op de script tags, maar een prima tweede optie is om de script tags helemaal onderaan de HTML-code te plaatsen.
Pas inladen wanneer nodig
Vaak wordt alle JavaScript van een website gebundeld in één bestand. Het nadeel hiervan is dat er waarschijnlijk veel code onnodig wordt ingeladen en verwerkt. Denk aan de JavaScript-code voor een widget die de bezoeker nooit op z’n scherm ziet. Voor onze klanten proberen we daarom afgebakende stukken JavaScript-code pas in te laden op het moment dat ze nodig zijn. Dus niet in één grote bundel, maar opgeknipt waar dat mogelijk is. Bijvoorbeeld een aparte bundel voor een widget of de ‘Mijn-omgeving’, die alleen wordt ingeladen op de benodigde pagina’s.
Sommige van onze nieuwe projecten, zoals voor shign.nl, zijn hier volledig op ingericht. Met tools als Webpack en Gatsbyjs serveren we JavaScript in kleine partjes. Elk blok of component heeft dan zijn eigen stukje JavaScript. Door lazy loading wordt dat deel pas ingeladen wanneer het (bijna) in beeld staat. Zo hoeft de code voor een widget helemaal onderaan de pagina niet te worden ingeladen als de gebruiker niet zo ver naar beneden scrolt. Op die manier wordt de browser minimaal belast met het downloaden en verwerken van JavaScript. En dat resulteert in veel snellere pagina’s.
Pas uitvoeren wanneer nodig
Maar ook wanneer het niet meer eenvoudig is om de JavaScript op te knippen in kleinere bestanden, kan het de moeite waard zijn om alleen de uitvoering van JavaScript code pas te laten plaatsvinden, wanneer het betreffende onderdeel in beeld verschijnt. Zo hebben we voor een van onze klanten een React-component kunnen lazy loaden, wat veel performance-winst opleverde. Die JavaScript-code voerde namelijk zelf weer API-calls uit en laadde verschillende afbeeldingen in. Door onze verbetering gebeurt dat dus nu pas wanneer het onderdeel in beeld verschijnt.
Met dit artikel heb je hopelijk een goed beeld gekregen van de wijze waarop JavaScript de snelheid van je website beïnvloedt. Je weet nu hoe je de performance van je website kunt beïnvloeden door minder en beter JavaScript-code in te laden. En hoe je zo zorgt voor een betere gebruikerservaring op mobile en hoger scoort in Google-zoekresultaten.
Heb je vragen over slimmer gebruik van JavaScript? Neem contact op, we helpen je graag. Stuur een mailtje naar info@avivasolutions.nl of bel met 071 710 74 74.
- performance
- javascript