14 metoder för att skjuta upp eller schemalägga JavaScript
Lär dig hur du skjuter upp och schemalägger JavaScript

Varför skjuta upp eller schemalägga JavaScript?
JavaScript kan (och kommer att) sakta ner din webbplats på flera sätt. Detta kan ha alla möjliga negativa effekter på Core Web Vitals. JavaScript kan konkurrera om nätverksresurser, det kan konkurrera om CPU- resurser (blockera huvudtråden) och det kan till och med blockera parsningen av en webbsida. Att skjuta upp och schemalägga dina skript kan drastiskt förbättra Core Web Vitals.
Table of Contents!
- Varför skjuta upp eller schemalägga JavaScript?
- Hur kan JavaScript-timing påverka Core Web Vitals?
- Hur väljer du rätt metod för uppskjutning?
- Metod 1: Använd defer-attributet
- Metod 2: Använd async-attributet
- Metod 3: Använd moduler
- Metod 4: Placera skript nära botten av sidan
- Metod 5: Injicera skript
- Metod 6: Injicera skript vid ett senare tillfälle
- Metod 7: Ändra skripttypen (och ändra sedan tillbaka)
- Metod 9: Använd readystatechange
- Metod 10: Använd setTimeout utan timeout
- Metod 11: Använd setTimeout med en timeout
- Metod 12: Använd ett promise för att skapa en microtask
- Metod 13: Använd en microtask
- Metod 15: Använd postTask
För att minimera de negativa effekterna som JavaScript kan ha på Core Web Vitals är det vanligtvis en bra idé att ange när ett skript ställs i kö för nedladdning och schemalägga när det kan ta upp CPU-tid och blockera huvudtråden.
Hur kan JavaScript-timing påverka Core Web Vitals?
Hur kan JavaScript-timing påverka Core Web Vitals? Ta bara en titt på detta verkliga exempel. Den första sidan laddas med 'renderingsblockerande' JavaScript. Målningsmåtten samt Time to interactive är ganska dåliga. Det andra exemplet är exakt samma sida men med JavaScript uppskjutet. Du kommer se att LCP-bilden fortfarande tog en stor smäll. Det tredje exemplet har samma skript exekverat efter sidans 'load event' och har funktionsanropen uppdelade i mindre bitar. Det sista klarar Core Web Vitals med marginal.



Som standard blockerar extern JavaScript i sidans head skapandet av renderingsträdet. Mer specifikt: när webbläsaren stöter på ett skript i dokumentet måste den pausa DOM-konstruktionen, överlämna kontrollen till JavaScript-runtime och låta skriptet köras innan DOM-konstruktionen fortsätter. Detta påverkar dina målningsmått (Largest Contentful Paint och First Contentful Paint).
Uppskjuten eller asynkron JavaScript kan fortfarande påverka målningsmått, särskilt Largest Contentful Paint eftersom det kommer att köras och blockera huvudtråden, när DOM har skapats (och vanliga LCP-element kanske inte har laddats ner).
Externa JavaScript-filer kommer också att konkurrera om nätverksresurser. Externa JavaScript-filer laddas vanligtvis ner tidigare än bilder. OM du laddar ner för många skript kommer nedladdningen av dina bilder att fördröjas.
Sist men inte minst kan JavaScript blockera eller fördröja användarinteraktion. När ett skript använder CPU-resurser (blockerar huvudtråden) kommer en webbläsare inte att svara på inmatning (klick, scrollning etc.) förrän skriptet har slutförts.
Hur löser schemaläggning eller uppskjutning av JavaScript Core Web Vitals?
Hur väljer du rätt metod för uppskjutning?
Inte alla skript är likadana och varje skript har sin egen funktionalitet. Vissa skript är viktiga att ha tidigt i renderingsprocessen, andra är det inte.

Jag brukar kategorisera JavaScripts i 4 grupper baserat på deras viktighetsgrad.
1. Renderingskritiskt. Dessa är skript som kommer att ändra utseendet på en webbsida. Om de inte laddas kommer sidan inte att se komplett ut. Dessa skript bör undvikas till varje pris. Om du inte kan undvika dem av någon anledning bör de inte skjutas upp. Till exempel en toppslider eller ett A/B-testningsskript.
2. Kritiskt. Dessa skript kommer inte att ändra utseendet på en webbsida (så mycket) men sidan fungerar inte bra utan dem. Dessa skript bör skjutas upp eller göras asynkrona. Till exempel dina menyskript.
3. Viktigt. Dessa är skript som du vill ladda eftersom de är värdefulla för dig eller besökaren. Jag brukar ladda dessa skript efter att load event har avfyrats. Till exempel analys eller en 'tillbaka till toppen'-knapp.
4. Trevligt att ha. Dessa är skript som du kan klara dig utan om det absolut behövs. Jag laddar dessa skript med lägsta prioritet och kör dem bara när webbläsaren är inaktiv. Till exempel en chattwidget eller en facebookknapp.
Metod 1: Använd defer-attributet
Skript med defer-attributet laddas ner parallellt och läggs till i JavaScript-kön för uppskjutna skript. Precis innan webbläsaren avfyrar DOMContentLoaded-eventet kommer alla skript i den kön att köras i den ordning de förekommer i dokumentet.
<script src='javascript.js'></script> 'Defer-tricket' löser vanligtvis många problem, särskilt målningsmåtten. Tyvärr finns det ingen garanti, det beror på kvaliteten på skripten. Uppskjutna skript körs när alla skript har laddats och HTML är parsad (DOMContentLoaded). LCP-elementet (vanligtvis en stor bild) kanske inte har laddats vid den tidpunkten och de uppskjutna skripten kommer fortfarande att orsaka en fördröjning i LCP.
När ska du använda detta:
Använd uppskjutna skript för kritiska skript som behövs så snart som möjligt.
Fördelar:
- Uppskjutna skript laddas ner parallellt
- DOM kommer att vara tillgängligt vid körningstillfället
Nackdelar:
- Uppskjutna skript kan fördröja dina LCP-mått
- Uppskjutna skript blockerar huvudtråden när de körs
- Det kanske inte är säkert att skjuta upp skript när inline- eller async-skript är beroende av dem
Metod 2: Använd async-attributet
Skript med async-attributet laddas ner parallellt och körs omedelbart efter att de har laddats ner.
<script src='javascript.js'></script> Async-skript gör lite för att lösa dina pagespeed-problem. Det är bra att de laddas ner parallellt men det är ungefär allt. När de har laddats ner blockerar de huvudtråden när de körs.
När ska du använda detta:
Använd async-skript för kritiska skript som behövs så snart som möjligt och är fristående (inte beroende av andra skript).
Fördelar:
- Async-skript laddas ner parallellt.
- Async-skript körs så snart som möjligt.
Nackdelar:
- DOMContentLoaded kan inträffa både före och efter async.
- Körningsordningen för skripten kommer att vara okänd i förväg.
- Du kan inte använda async-skript som är beroende av andra async- eller uppskjutna skript
Metod 3: Använd moduler
Modulära skript skjuts upp som standard om de inte har async-attributet. I så fall behandlas de som async-skript
<script src='javascript.js'></script> Moduler är ett nytt sätt att tänka kring JavaScript och åtgärdar vissa designbrister. Utöver det kommer användning av skriptmoduler inte att snabba upp din webbplats.
När ska du använda detta:
När din applikation är byggd på ett modulärt sätt är det logiskt att också använda JavaScript-moduler.
Fördelar:
- Moduler skjuts upp som standard
- Moduler är lättare att underhålla och fungerar utmärkt med modulär webbdesign
- Moduler möjliggör enkel koddelning med dynamiska importer där du bara importerar de moduler du behöver vid en viss tidpunkt.
Nackdelar:
- Moduler i sig förbättrar inte Core Web Vitals
- Att importera moduler just-in-time eller i farten kan vara långsamt och försämra FID och INP
Metod 4: Placera skript nära botten av sidan
Skript i sidfoten ställs i kö för nedladdning vid en senare tidpunkt. Detta prioriterar andra resurser som finns i dokumentet ovanför skripttaggen.
<html>
<head></head>
<body>
[your page contents here]
<script defer src='javascript.js'></script>
</body>
</html> Att placera dina skript längst ner på sidan är en intressant teknik. Detta schemaläger andra resurser (som bilder) före dina skript. Detta ökar chansen att de är tillgängliga för webbläsaren och målade på skärmen innan JavaScript-filerna har laddats ner och huvudtråden blockeras av skriptkörning. Ändå ... ingen garanti.
När ska du använda detta:
När dina skript redan presterar ganska bra men du vill prioritera andra resurser som bilder och webbtypsnitt något.
Fördelar:
- Att placera skript längst ner på sidan kräver inte mycket kunskap.
- Om det görs korrekt finns det ingen risk att detta förstör din sida
Nackdelar:
- Kritiska skript kan laddas ner och köras senare
- Det åtgärdar inga underliggande JavaScript-problem
Metod 5: Injicera skript
Injicerade skript behandlas som async-skript. De laddas ner parallellt och körs omedelbart efter nedladdning.
<script>
const loadScript = (scriptSource) => {
const script = document.createElement('script');
script.src = scriptSource;
document.head.appendChild(script);
}
// call the loadscript function that injects 'javascript.js'
loadScript('javascript.js');
</script> Ur ett Core Web Vitals-perspektiv är denna teknik exakt densamma som att använda <script async>.
När ska du använda detta:
Denna metod används ofta av tredjepartsskript som triggas så tidigt som möjligt. Funktionsanropet gör det enkelt att kapsla in och komprimera kod.
Fördelar:
- Inkapslad kod som injicerar ett async-skript.
Nackdelar:
- DOMContentLoaded kan inträffa både före och efter att skriptet har laddats.
- Körningsordningen för skripten kommer att vara okänd i förväg.
- Du kan inte använda detta på skript som är beroende av andra async- eller uppskjutna skript
Metod 6: Injicera skript vid ett senare tillfälle
Trevligt-att-ha-skript bör enligt min mening aldrig laddas uppskjutet. De bör injiceras vid det mest lämpliga tillfället. I exemplet nedan kommer skriptet att köras efter att webbläsaren har skickat 'load'-eventet.
<script>
window.addEventListener('load', function () {
// see method 5 for the loadscript function
loadScript('javascript.js');
});
</script> Detta är den första tekniken som tillförlitligt förbättrar Largest Contentful Paint. Alla viktiga resurser, inklusive bilder, kommer att ha laddats ner när webbläsaren avfyrar 'load event'. Detta kan introducera alla möjliga problem eftersom det kan ta lång tid innan load event anropas.
När ska du använda detta:
För trevligt-att-ha-skript som inte har någon anledning att påverka målningsmåtten.
Fördelar:
- Konkurrerar inte om kritiska resurser eftersom skriptet injiceras när sidan och dess resurser har laddats
Nackdelar:
- Om din sida är dåligt designad ur Core Web Vitals-synpunkt kan det ta lång tid innan sidan skickar 'load'-eventet
- Du måste vara försiktig med att inte tillämpa detta på kritiska skript (som lazy loading, meny etc.)
Metod 7: Ändra skripttypen (och ändra sedan tillbaka)
Om en skripttagg hittas någonstans på sidan som 1. har ett type-attribut och 2. type-attributet inte är "text/javascript" kommer skriptet inte att laddas ner och köras av webbläsaren. Många JavaScript-laddare (som CloudFlares RocketLoader) förlitar sig på denna princip. Idén är ganska enkel och elegant.
Först skrivs alla skript om så här:
<script src="javascript.js"></script> Sedan, vid någon punkt under laddningsprocessen konverteras dessa skript tillbaka till 'vanliga javascripts'.
När ska du använda detta:
Detta är inte en metod jag skulle rekommendera. Att åtgärda JavaScript-påverkan kräver mycket mer än att bara flytta varje skript lite längre ner i kön. Å andra sidan, om du har liten kontroll över skripten som körs på sidan eller har otillräcklig JavaScript-kunskap kan detta vara ditt bästa alternativ.
Fördelar:
- Det är enkelt, aktivera bara rocket loader eller ett annat plugin så körs alla dina skript vid en något senare tidpunkt.
- Det kommer troligen att åtgärda dina målningsmått förutsatt att du inte använder JS-baserad lazy loading.
- Det fungerar för inline- och externa skript.
Nackdelar:
- Du har ingen finkornig kontroll över när skripten körs
- Dåligt skrivna skript kan gå sönder
- Det använder JavaScript för att lösa JavaScript
- Det gör inget åt långkörande skript
Metod 8: Använd intersection observer
Med intersection observer kan du köra en funktion (som i detta fall laddar ett externt JavaScript) när ett element scrollas in i det synliga vyportalen.
<script>
const handleIntersection = (entries, observer) => {
if (entries?.[0].isIntersecting) {
// load your script or execute another
function like trigger a lazy loaded element
loadScript('javascript.js');
// remove the observer
observer.unobserve(entries?.[0].target);
}
};
const Observer = new window.IntersectionObserver()
Observer.observe(document.querySelector('footer'));
</script> Detta är överlägset den mest effektiva metoden för att skjuta upp JavaScript. Ladda bara de skript du behöver, precis innan du behöver dem. Tyvärr är verkligheten sällan så ren och inte många skript kan kopplas till ett element som scrollas in i vyn.
När ska du använda detta:
Använd denna teknik så mycket som möjligt! Närhelst ett skript bara interagerar med en komponent utanför skärmen (som en karta, en slider, ett formulär) är detta det bästa sättet att injicera skriptet.
Fördelar:
- Stör inte Core Web Vitals LCP och FCP
- Injicerar aldrig skript som inte används. Detta förbättrar FID och INP
Nackdelar:
- Bör inte användas med komponenter som kan vara i det synliga vyportalen
- Svårare att underhålla än vanlig <script src="...">
- Kan introducera en layout shift
Metod 9: Använd readystatechange
document.readystate kan användas som ett alternativ till 'DOMContentloaded'- och 'load'-eventet. Det 'interactive' readystate är vanligtvis en bra plats att anropa kritiska skript som behöver ändra DOM eller lägga till eventhanterare.
Det 'complete' ready state är en bra plats att anropa skript som är mindre kritiska.
document.addEventListener('readystatechange', (event) => {
if (event.target.readyState === 'interactive') {
initLoader();
} else if (event.target.readyState === 'complete') {
initApp();
}
}); Metod 10: Använd setTimeout utan timeout
setTimeout är en ogillad men kraftigt underskattad metod i pagespeed-communityt. setTimeout har fått dåligt rykte eftersom det ofta missbrukas. Många utvecklare tror att setTimeout bara kan användas för att fördröja skriptkörning med det angivna antalet millisekunder. Även om detta stämmer gör setTimeout faktiskt något mycket mer intressant. Det skapar en ny uppgift i slutet av webbläsarens event loop. Detta beteende kan användas för att schemalägga dina uppgifter effektivt. Det kan också användas för att dela upp långa uppgifter i separata mindre uppgifter
<script>
setTimeout(() => {
// load a script or execute another function
console.log('- I am called from a 0ms timeOut()')
}, 0);
console.log('- I was last in line but executed first')
/*
Output:
- I was last in line but executed first
- I am called from a 0ms timeOut()
*/
</script> När ska du använda detta:
setTimeout skapar en ny uppgift i webbläsarens event loop. Använd detta när din huvudtråd blockeras av många funktionsanrop som körs sekventiellt.
Fördelar:
- Kan dela upp långkörande kod i mindre delar.
Nackdelar:
- setTimeout är en ganska grov metod och erbjuder inte prioritering av viktiga skript.
- Lägger till koden som ska köras i slutet av loopen
Metod 11: Använd setTimeout med en timeout
Det blir ännu mer intressant när vi anropar setTimeout med en timeout på mer än 0ms
<script>
setTimeout(() => {
// load a script or execute another function
console.log('- I am called from a 10ms timeOut()')
}, 10);
setTimeout(() => {
// load a script or execute another function
console.log('- I am called from a 0ms timeOut()')
}, 0);
console.log('- I was last in line but executed first')
/*
Output:
- I was last in line but executed first
- I am called from a 0ms timeOut()
- I am called from a 10ms timeOut()
*/
</script> När ska du använda detta:
När du behöver en enkel metod för att schemalägga ett skript efter ett annat räcker en liten timeout
Fördelar:
- Stöds i alla webbläsare
Nackdelar:
- Erbjuder inte avancerad schemaläggning
Metod 12: Använd ett promise för att skapa en microtask
Att skapa en microtask är också ett intressant sätt att schemalägga JavaScript. Microtasks schemaläggs för körning omedelbart efter att den aktuella körningsloopen har avslutats.
<script>
const myPromise = new Promise((resolve, reject) => {
resolve();
}).then(
() => {
console.log('- I was scheduled after a promise')
}
);
console.log('- I was last in line but executed first')
/*
Output:
- I was last in line but executed first
- I was scheduled after a promise
*/
</script> När ska du använda detta:
När en uppgift behöver schemaläggas omedelbart efter en annan uppgift.
Fördelar:
- Microtasken schemaläggs omedelbart efter att uppgiften har körts klart.
- En microtask kan användas för att fördröja mindre viktiga delar av JavaScript-kod i samma event.
Nackdelar:
- Delar inte upp huvudtråden i mindre delar. Webbläsaren har ingen chans att svara på användarinmatning.
- Du kommer troligen aldrig behöva använda microtasks för att förbättra Core Web Vitals om du inte redan vet exakt vad du gör.
Metod 13: Använd en microtask
Samma resultat kan uppnås genom att använda queueMicrotask(). Fördelen med att använda queueMicrotask() framför ett promise är att det är något snabbare och du behöver inte hantera dina promises.
<script>
queueMicrotask(() => {
console.log('- I am a microtask')
})
console.log('- I was last in line but executed first')
/*
Output:
- I was last in line but executed first
- I am a microtask
*/
</script> Metod 14: Använd requestIdleCallback
Metoden window.requestIdleCallback() ställer en funktion i kö som anropas under webbläsarens inaktiva perioder. Detta gör det möjligt för utvecklare att utföra bakgrunds- och lågprioritetsarbete på huvud-event loopen, utan att påverka latenskritiska händelser som animation och inmatningssvar. Funktioner anropas generellt i först-in-först-ut-ordning; dock kan callbacks med angiven timeout anropas i annan ordning vid behov för att hinna köra dem innan timeouten löper ut.
<script>
requestIdleCallback(() => {
const script = document.createElement('script');
script.src = 'javascript.js';
document.head.appendChild(script);
});
</script> När ska du använda detta:
Använd detta för skript som är trevliga att ha eller för att hantera icke-kritiska uppgifter efter användarinmatning
Fördelar:
- Kör JavaScript med minimal påverkan på användaren
- Kommer med största sannolikhet att förbättra FID och INP
Nackdelar:
- Stöds i de flesta webbläsare men inte alla. Det finns polyfills som faller tillbaka på setTimeout();
- Ingen garanti att koden någonsin körs
Metod 15: Använd postTask
Metoden tillåter användare att valfritt ange en minsta fördröjning innan uppgiften körs, en prioritet för uppgiften och en signal som kan användas för att ändra uppgiftens prioritet och/eller avbryta uppgiften. Den returnerar ett promise som löses med resultatet av uppgiftens callback-funktion, eller avvisas med avbrottsorsaken eller ett fel som kastas i uppgiften.
<script>
scheduler.postTask(() => {
const script = document.createElement('script');
script.src = 'javascript.js';
document.head.appendChild(script);
}, { priority: 'background' });
</script> När ska du använda detta:
postTask är det perfekta API:et för att schemalägga skript med. Tyvärr är webbläsarstödet för närvarande dåligt så du bör inte använda det.
Fördelar:
- Fullständig kontroll över schemaläggning av JavaScript-körning!
Nackdelar:
- Stöds inte i vissa viktiga webbläsare.
Urgent Fix Required?
Google Search Console failing? I offer rapid-response auditing to identify the failure point within 48 hours.
- 48hr Turnaround
- Rapid Response
- Failure Identification

