Test the effect of async and request blocking with two scripts which ruin Largest Contentful Paint and Cumulative Layout Shift on purpose.

While searching for a more automated method to learn about the effects of request blocking single Javascripts on web vitals KPIs I had of course some weird unexplainable numbers. So decided to not use real websites anymore, but test conditions and two scripts to fake bad LCP and bad CLS performance. Some learnings:

The “bad KPIs on purpose”-scripts

LCP is a speed KPI. So it should become worse with loading a really big JS file.

const goLCP = () => {
const x = [a huge array full stuff... In my case 9 MB big]
document.addEventListener("DOMContentLoaded", function(event) {

CLS is a litte bit harder. I need to make your website move weirdly and not look stable. Something like this:

The element with id=”moving” is the moving object, which bounces around if you enable this script.

let sleepCLS = m => new Promise(r => setTimeout(r, m))const goCLS = async() => {
for (i = 0; i < 100000; i++) {
document.getElementById("moving").style.padding = "10em";
await sleepCLS(100)
document.getElementById("moving").style.padding = "1em";
await sleepCLS(100)
document.addEventListener("DOMContentLoaded", function(event) {

If you want to see both scripts live: http://tobiaswillmann.de/fuckupwebvitals/indexBothasync.html


Now we want to find out what happens if request blocking is used in different async szenarios.

Let’s start easy. Here are some async variations but the two bad scripts are not request blocked.

It gets interesting if you start loading async. As expected loading the fuckupLCP.js async lowered the LCP at lot. A huge script wasn’t blocking anymore.

To load fuckupCLS async had of course no effect. CLS is a KPI which measures measures visual stability, which has almost nothing to do with the loading performance KPI LCP.

What’s interesting is the negative impact on CLS if fuckupLCP.js is loaded async. My interpretation for now is that fuckupCLS.js is able the ruin CLS better and faster with LCP being not interrupting it. Reasonable? What do you think?

Let’s check what happens if you really block the requests of the script which ruins CLS compared to loading everything.

As expected CSL scores improve if you don’t load the ruin script anymore. The all go down to zero. So the first learning here is (again) good CLS scores come from not having scripts, which cause visual instability.

Interesting here is that to load the fuckupLCP.js async is roughly as good as request blocking it to improve LCP.

Still curious here why CLS went worse …

Test data of 10 runs each. With slowed down network and CPU using Puppeteer.

Head of #SEO at Blick.ch