Determine webpage load speed using Javascript and the window.performance.timing method

Utilizing Selenium in C#, I have devised a method to calculate page load times, as demonstrated by the code snippet below:

Code: Selenium C#

using OpenQA.Selenium;
double requestStart = (long)((IJavaScriptExecutor)CTest.Driver).ExecuteScript("return window.performance.timing.requestStart");
double domComplete = (long)((IJavaScriptExecutor)CTest.Driver).ExecuteScript("return window.performance.timing.domComplete");
var totaltime = domComplete - requestStart;

After some experimentation, I discovered that the variable totaltime in the code above corresponds to the value of Load as depicted in the image below. It seems that Load always matches the value of the DOMContentLoaded variable.

Question:

  1. Why does the value for Finish not match the same time? What does Finish represent and how can it be calculated using JavaScript's window.performance.timing object?
  2. How can the time between typing a URL into a web browser (and pressing enter) and when all the content on the page is fully loaded be calculated?

The document linked below provides a good description of what each timing variable measures in terms of resource loading timestamps, however, the Finish value in Chrome DevTools is causing confusion.

Figure: Extracting Performance information from Chrome's Devtool (F12) Network tab

https://i.sstatic.net/nHFWA.png


Edit:

Thank you @wOxxOm. I observed that the Finish time continuously increased as I interacted with the website, visiting different pages within the site. On the other hand, the DOMContentLoaded and Load values remained constant even after the initial loading event. This aligns with what you mentioned in your response. Following your suggestion, I updated my code to:

double connectStart = (long)((IJavaScriptExecutor)CTest.Driver).ExecuteScript("return window.performance.timing.connectStart");
double loadEventEnd = (long)((IJavaScriptExecutor)CTest.Driver).ExecuteScript("return window.performance.timing.loadEventEnd");
double newMeasure = (loadEventEnd - connectStart) / 1000.0;

I have also started exploring the LCP feature in Chrome 77.

I have another question:

Question 2: Initially, I expected the values within the window.performance object to change with new values as I navigated through the website by clicking on different links. However, all the window.performance values remained static after the initial website load (DOMContentLoaded and Load values in Chrome’s devtool network window also did not change as I navigated the site). Why did the window.performance values remain unchanged? Could this be due to the nature of the website being a Single Page Application (SPA)? In contrast, I noticed that when I navigated through a different, older website, the DOMContentLoaded and Load times changed to reflect the loading times for each page within that site as I clicked on links in the main menu.

Answer №1

Why is the difference between 'finished' and 'domComplete - requestStart'?

DOMContentLoaded signifies that all the DOM content has loaded, but javascript and images are still in the process of loading.

Load indicates that all the content, including javascript and images, has been fully loaded. By initiating lazy loading of images and javascript prior to this event, it can lead to a delay in the load event and hinder the overall page speed. This can have a negative impact on your google lighthouse score.

Finished in chrome dev tools encompasses async loading of assets, which may continue to download even after the onload event has occurred. When additional content is loaded through scripts via ajax, the finished time will increase. This metric is crucial in determining the time taken to load all the content, including lazily loaded images, scripts, etc., which should ideally be loaded post the load event to enhance your page's SEO.

How do you measure the time from entering a URL in a web browser to the full page load?

The pivotal event to focus on, particularly for search engines, is the load event. Hence, the finish time holds less significance. The aim is to defer loading any content that is not required for the initial user interaction with your app until after the load event is triggered.

It is advisable to pay attention to navigationStart instead of requestStart. There is a time gap between when the user hits enter (navigationStart) and when the actual request is initiated (requestStart).

Referencing the W3C spec:

navigationStart

This attribute must return the time immediately after the user agent finishes prompting to unload the previous document. If there is no previous document, this attribute must return the time the current document is created.

Quoting MDN:

performance.timing.navigationStart + performance.now() will be approximately equal to Date.now()

Utilizing performance.now() at onload helps determine the duration taken to reach that point. However, this method lacks support in IE9 and some browsers round off the results. The more consistent choice is to use

Date.now() - window.performance.timing.navigationStart
, which is compatible with IE9.

JavaScript snippet for logging the load event time.

window.addEventListener('load', (event) => {
    console.log('All assets are loaded')
    console.log(Date.now() - window.performance.timing.navigationStart);
});

Why do window.performance values remain constant post initial load?

This phenomenon is common in Single Page Applications (SPAs). Once the DOM and initial assets are loaded, any subsequent content is fetched asynchronously. Routing in SPAs is managed on the client side and does not trigger a fresh page load in chrome dev tools. Even upon manually reloading the page, the 'preserve log' option in the network tab must be disabled to obtain updated performance values.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to send a parameter to a mousewheel event?

for (var i = 0; i < 10; i++) { $('#content-scroll' + i).mousewheel(function(event, delta) { if (delta > 0) sliderUp(i - 1); else if (delta < 0) sliderDown(i - 1); return false; // prevent default }); } I am facing an iss ...

In Next.js, encountering an error when using canvas drawImage

I am attempting to upload a local image onto a canvas element, but I keep encountering an error: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement ...

Issues with Firebase-admin preventing writing to the database are occurring without any error messages being displayed

Issues with Firebase admin writing to the database. The database is instantiated as follows: var db = admin.database(); A reference to the desired table is then set up: var systemsRef = db.ref("systems/"); A function is created to check if a 'sys ...

Efficiently sending VueJS data to a separate script

I am in the process of transitioning an existing site to VueJS, but I have encountered a roadblock when it comes to finding the best method to accomplish this task. The site currently utilizes D3-Funnel (https://github.com/jakezatecky/d3-funnel) to genera ...

Guide to updating information in Firestore using Node.js, embedded in a map array

Encountered an issue with the following error message: Error: Unable to access 'set' property of undefined. I am attempting to update the endTime field in my script for each user, calculate total hours worked, and then update the 'totalTi ...

Troubleshooting problems with background-image in CSS using Javascript

My latest project involves coding to assign background images to various classes using jQuery. The image files are named in a numerical order, such as 0bg.jpg, 1bg.jpg, 2bg.jpg, and so on. for (i=0; i < 8; i++) { $('.hpCarousel:eq('+i+' ...

Tips for injecting scripts into the head tag after an Angular component has been loaded

Currently, I am facing an issue with a script tag containing a Skype web control CDN. The script has been placed in the head section of my index.html file, but it is being called before the component that needs it has finished loading. Does anyone have a ...

Modify the color of a div element in React when it is clicked on

My goal is to change the color of each div individually when clicked. However, I am facing an issue where all divs change color at once when only one is clicked. I need help in modifying my code to achieve the desired behavior. Below is the current implem ...

Mobile Menu in wordpress stays visible after being clicked

I recently created a one-page layout that includes some links. However, when I view the site on my smartphone and open the main menu using the button to click on a link (which scrolls within the same page), I noticed that the mobile menu remains visible a ...

PHP - Offline/Online Status Polling Protocol Guide for Beginners

I am in search of a solution to track the online and offline status of users on my website. My site is a single page with no clickable links, so users may leave their tabs open for long periods without interaction. It is not essential to pinpoint the exact ...

dynamic rendering in React based on the value passed through props

I am attempting to render a component using react.lazy, where the path is a variable in my props. However, I am encountering an error with webpack. The parent component sends the props like this: <DynamicModal url = 'Impuesto/formulario&apo ...

What is the best way to modify a current state object without causing an endless loop of redirects?

const useCase = (argument) => { const [value, setValue] React.useState(argument) React.useEffect(() => setValue({...value ...argument), [argument, value, setValue]) } The above code is currently causing an infinite loop due to setting the stat ...

The value of a select box cannot be retrieved until it has been clicked on

I am working with a selectBox element in my code: <select class="span2" name="filterYear" id="filterYear" style="margin-right:10px;"> <% for (var i = 0; i < years.length; i++) { %> <% if (years[i] == selectedYear) { %> ...

Encountering a JSLint error while attempting to import the 'aws-amplify' package in my main file

Recently, I installed the latest version of aws-amplify using npm. After running npm init with 'entryPoint.js' as the entrypoint file, I encountered an issue when pasting the following code at the top of entryPoint.js: import Amplify, {Auth} from ...

Navigating the path for the script src dynamically with the help of Angular.js and Javascript

I could really use some assistance. I am trying to dynamically set the js/css path name using Angular.js/Javascript/Jquery. Let me explain my code below. <script src="/crm/controller/productController.js" type="text/javascript"></script> Let& ...

What is the best way to scrape information from a real-time website using Python?

One thing that has been on my mind is how to retrieve real-time data from a website using Python. Want to check out the website to see what I mean? Here's the link: ...

Angular 2 Mixup: Using Leaflet and Google Maps with Incorrect Tile Order

I am encountering an issue while working on Leaflet and Google within Angular 2. The problem lies in the Tilemill tiles not rendering properly as they are displaying in a strange order. Here is a screenshot of the current state: https://i.stack.imgur.com/ ...

Create a new button dynamically within an HTML table row using pure JavaScript programming techniques

Currently, I am retrieving JSON data from an API and then displaying this data in an HTML table using plain JavaScript. My goal is to dynamically add a button at the end of each row for additional functionality, but so far, I have been unable to figure out ...

What techniques can I use to merge alpha channels with compositing in images?

Utilizing an HTML5 Canvas along with the KineticJS(KonvaJS) canvas library, I have successfully incorporated an Image element. My current objective is to erase specific pixels while maintaining a certain level of transparency. The red dot erases pixels at ...

Having trouble with AngularJS not rendering on your HTML page?

This question has probably been asked countless times, but I'm genuinely unsure about what I'm doing wrong. The solutions I've come across so far haven't fixed the issue for me. Just to provide some context, I'm currently followin ...