Search code examples
javascriptperformance-testinglighthousepartytown

Lighthouse Total Blocking Time Always 0ms


I've been trying to implement this tutorial to get started familiarizing myself with Partytown. I'm trying to compare the performance with and without Partytown however when analyzing page load using Lighthouse without implementing anything Partytown related, the total blocking time is always 0ms.

The following is the html file running in the vanilla js vite project.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <h1>
      Website Content
    </h1>

    <script>
      console.log('begin operation privacy invasion XD');

      let i = 999999999;
      while (i--){
        //do nothing important
      }

      console.log('privacy invasion complete');

      document.body.appendChild(document.createTextNode('something cleaver'));

    </script>
    <script type="module" src="/main.js"></script>
  </body>
</html>

I'd expect it to have a total blocking time of ~1,400ms but definitely not 0.

Screenshot of the lighthouse report

I've tried changing the value of i but no matter what the page always says 0ms.

Does anyone know what is wrong or if I'm misreading the results from the lighthouse report?


Solution

  • You've hit a couple of browser nuances here.

    TBT is defined as:

    The Total Blocking Time (TBT) metric measures the total amount of time between First Contentful Paint (FCP) and Time to Interactive (TTI) where the main thread was blocked for long enough to prevent input responsiveness.

    The theory being that, before FCP, the user will not try to interact with the page so blocking time matters less.

    Your page is so simple, that the browser see the <h1> and then the <script> closely enough together that it decides to process both together.

    This means the FCP doesn't actually happen until after the script has run. Hence no TBT. You can see this with a performance trace:

    Performance trace

    You'll also notice in Lighthouse that the first image drawn includes both the <h1> and the dynamically inserted 'something cleaver' text:

    Lighthouse filmstrip

    Could the browser be cleverer here and paint the h1 first? Maybe, but it doesn't know the script is going to be a long one so there's a balance between doing paints often (costs more processing time) or less (less processing time, but less frequent updates).

    You could change your blocking script to use a setTimeout to not block this frame:

    
        <script>
          console.log('begin operation privacy invasion XD', performance.now());
    
          setTimeout(() => {
              let i = 999999999;
              while (i--){
                //do nothing important
              }
    
              console.log('privacy invasion complete', performance.now());
    
              document.body.appendChild(document.createTextNode('something cleaver'));
          }, 0);
    
        </script>
    

    Then it's a non-blocking script and the browser continues on, does and initial paint, and then runs the script. And only then it becomes blocking.

    Then you see a large TBT, and the filmstrip shows the initial H1 being drawn (FCP), and then the extra text:

    Lighthouse report

    Also doing a performance trace shows the FCP happening before the script:

    Updated performance profile