Calculate Page Load Times using Javascript's window.performance.timing - javascript

I am able to calculate page load times in selenium with the following code:
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;
Through trail and error, I was able to determine that totaltime the above code corresponds to the value Load in the below picture. Load in image always seems to be the same as the value of DOMContentLoaded variable.
Question:
Why is value for Finish not the same time? What is Finish and how do you calculate this using javascript's window.performance.timing object?
How do you calculate the time between typing a url into a web browser (and hitting enter) and the time when all content on the page is finally loaded?
The following document was pretty good at describing what each timing variable was measuring
mozilla-developer timestamp variables, but the Finish value in chrome devtools is muddying the water.
Figure: Extracting Performance information from Chrome's Devtool (F12) Network tab
Edit:
Thanks #wOxxOm. I noticed that the Finish time kept increasing as I interacted with the website (went to different pages in the website) whereas DOMContentLoaded and Load never changed after the initial load event. This corresponds to what you say in your response.
I switched to using the following code as you suggested:
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;
Also started looking into LCP feature in Chrome 77.
I did have one more question
Question 2:
I initially thought the values within the window.performance object would be repopulated with new values (times) as I clicked on a link (on the website) which would take me to a different page within the same website. However, all the window.performance values never change after the initial load of the website (DOMContentLoaded and Load values within Chrome’s devtool network window also never changed when maneuvering around in the website).
Question: Why did the values from window.performance never change? Was it because this is a SPA (Single Page Application)? I observed chrome devtool’s DOMContentLoaded and Load values when clicking around in a different website (older) and each time I went to a new page within that website, the DOMContentLoaded and Load times changed to show load time for every page within the website (went to different pages by clicking a link in the main menu of that website).

Why is finished not equal domComplete - requestStart?
DOMContentLoaded means all the DOM content is loaded, but javascript and images are still loading.
Load means all the content including javascript and images are loaded. If you start lazy loading images and javascript before this event has been fired, it will delay this event and slow down your page load event. This will have a negative effect on your google lighthouse score.
Finished in chrome dev tools include asynchronously loading assets, which may continue downloading way after the onload event has been fired. As soon as one of your scripts start loading more content via ajax, the finished time will increase. This number should generally help you to see how long it takes to load all the content, including lazy loaded images, scripts ect. which can and should be loaded after the load event to improve your page for SEO.
How to calculate the time between typing a url into a web browser and page being loaded?
The real important event, which search engines look at, is the load event. So you do not really care about the finish time. You want to move all content, which is not needed for the first interaction with your app, to be lazy loaded after this event has been fired.
Furthermore you are looking for navigationStart rather than requestStart. There will be some time between user pressing enter (navigationStart) and the request actually being executed (requestStart).
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.
MDN quote
performance.timing.navigationStart + performance.now() will be
approximately equal to Date.now()
Firing performance.now() onload tells you how long it took to get there.
However it is not supported by IE9 and some browsers round the results. Using Date.now() - window.performance.timing.navigationStart gives more consistent results and is supported by IE9.
JS for logging the time of load event.
window.addEventListener('load', (event) => {
console.log('All assets are loaded')
console.log(Date.now() - window.performance.timing.navigationStart);
});
Why window.performance values never change after the initial load?
This is related to SPA pages. Once the DOM and initial assets are loaded, everything else is loaded async. Routing for SPAs is handled in the frontend and does not trigger a new page load in chrome dev tools. Even when manually reloading the page, you have to disable the 'preserve log' option in the network tab to get fresh performance values.

Related

Javascript not executing immediately?

I have a javascript in a form of an extension on my Brave, that is connected to the authotkey commands, when I press a button the script will activate and constantly check for the button on a website, I refresh the website and the button appears, javascript clicks the button... Perfect...
Only sometimes, for no reason what so ever, it wont click it until full page is loaded and its slow to execute, other times it works in 0.1 seconds and clicks the button soon as it appears in the elements, I have tried a million things, even going so far to reinstall Windows, I do not change the code nothing in the code changes, the script sometimes works before site loads really fast, and sometimes waits for the whole page to load before clicking it. (It will usually work for few hours or days and then stop working)
My internet is fiber optics always same Ms and 0 jitter.
ANY TOUGHTS?
It might not be something on your end.
Sometimes, one element on the page that's getting loaded will take longer to load for reasons that are not under your own control - for example images loaded from a 3rd party source, like ads. This can cause delays in other dependent processes (that includes your script). However,
if you update your question with reproduction instructions we might be able to determine why, and,
in hindsight, it does sound like a load event being delayed, and it might be possible to change the script reference point to be a DOMContentLoaded event which fires sooner and should be enough for your script to start clicking stuff.

Using external javascript code to run a snippet on the Chrome console

Is it possible in an external javascript code (for example, a userscript through tampermonkey) to run a code snippet on the Chrome console. For example, console.log prints text to the console. Is there some way, like a function console.eval or some more complex way where I can run code on the console without manually opening it on the given website, but using the original javascript code behind the website or a userscript?
Notes: I use Google Chrome on Windows 10. Preferably this answer should be as generally applicable as possible, but first priority for me is for it to work in my environment.
Thanks,
Mike
Uk, when i said if the page is reloading constantly, the "console" that u think of would also reload??, a lot of us knew about what I'm doing below(if not all of us) but I finally connected it with your question. Using one tab to control the other tab
ONE EDIT: I used an interval to determine if the controlled tab is CLOSED(since a certain value eventually changes if the tab is closed for good)
HOW TO USE:
Open a tab with the same origin as desired url(but not the constantly reloading site)..
eg: opening a tab on "https://example.com/404" if desired url is "https://example.com" is the desired url(the constantly reloading one)
In the code snippet I have below, you can put your tab controlling code in the loadFn function, where myWindow and this point to the controlled tab's window
eg: in the loadFn function, myWindow.console.log(1) or this.console.log(1) would both log 1 to the controlled tab's console
SECOND EDIT: I shall explain how it works(and talk about unloadFn as you requested in comments)
I use a combination of unload and load listening to be able to repeatedly send code "on reload" which is not an event in itself so I had to create it. In case I didn't explain myself, I'd go into detail now..
When a page is reloading(or when I'm JUST SPAWNING the page, eg: var myWindow=window.open(desiredUrl)), the unload event happens. There's just one problem however; every time the page is reloading, all event listeners and any code you put is removed(because reload unloads to then reload)
The solution is simple: on every unload, I set the listners again, and since the function would call itself(every time the page unloads), the listeners would successfully be reloaded every time the page reloads(and that is why loadFn could run in the other tab after every reload)
DO NOTE: You might ask "why use a setTimeout then?". Actually it's quite important. Without the setTimeout, the event listeners DO NOT GET ADDED, I think it's because the tab would ignore your commands(since it would be focusing on loading its default stuff(like event listeners for instance)), and asynchronous programming does wonders in this case because it will wait until the other stuff are processed(like event handling stuff) then run
SIDE NOTE: If that's not why setTimeout works and NOT USING it doesn't, all I know is that without it, it doesn't work, and with it, it works
var myWindow=window.open(desiredUrl) //remember to run this code on the same origin as the desiredUrl
function loadFn(){
//this will happen every time myWindow loads or reloads
myWindow.alert("It runs in the controlled tab")
myWindow.console.log("Even in the controlled tab's console it works >:D")
}
function unloadFn(){setTimeout(()=>{
myWindow.addEventListener('unload',unloadFn)
myWindow.addEventListener('load',loadFn)
if(!myWindow.Window){console.warn("myWindow was CLOSED")}
},0)}
myWindow.addEventListener('unload',unloadFn)
//extra thing below to tell if controlled tab is closed >:D
var i=setInterval(()=>{
//for if controlled tab is closed
if(!myWindow.document.location){clearInterval(i);console.warn("myWindow was CLOSED")}
},0)

Chrome extension update flow

I am starting with chrome extension development and have a couple of questions regarding extension install/update flow and testing during the development :
What happens with the background script after extension update, does chrome perform background script reload ?
Are content scripts detached from background script after extension update ?
If there's an onInstalled event handler in background script, what happens with that event handler when chrome updates extension(is this event handler detached, and when update finishes, the new handler is attached and then executed or some other flow is exercised) ?
Is there a way to simulate update process during development in order to debug events that happen during the update process, for example to host extension on some local server and update from there ?
where to search for documentation on topics like this and similar, is the chromium source code the right place or at least the starting point ?
Thanks!
What happens with the background script after extension update, does Chrome perform background script reload?
The behavior depends on whether you have a handler to chrome.runtime.onUpdateAvailable event registered and whether your extension has a persistent background page or event page.
If you have a persistent background page:
If you handle this event and call chrome.runtime.reload(), the extension is unloaded and then updated before being loaded again.
If you handle this event and do not call chrome.runtime.reload(), then the update will only apply when the extension is next reloaded - likely the next full browser restart.
If you do not handle this event at all, the extension will be unloaded immediately to be updated.
If you have a non-persistent Event page:
If you handle this event and call chrome.runtime.reload(), the extension is updated before being loaded again.
If you do not call chrome.runtime.reload(), or do not handle the event at all, Chrome will update the extension when the Event page next gets unloaded.
There is no way to programmatically prevent the update once the background page gets unloaded for whatever reason.
Are content scripts detached from background script after extension update?
Yes, and it's not pretty. They enter an "orphaned" state when using Chrome API gives inconsistent errors (some do nothing, some trigger exceptions), but are still running — for example, any DOM event listeners will still trigger.
As such, if you want the content scripts to work immediately again, your job is to:
Inject scripts programmatically in existing tabs, without making an assumption that it did not execute before: cleanup first if necessary.
Make sure orphaned copies stop executing: either by noticing in the old copy that it's orphaned, or by broadcasting a DOM event from the new copy.
Important note about WebExtensions: Firefox, unlike Chrome, always reinjects content scripts on load into pages that match manifest entries. Make sure to take that into account.
There are a few question that cover this; for example:
Sending message from a background script to a content script, then to a injected script (See addendum to the answer)
How to properly handle chrome extension updates from content scripts
Chrome extension content script re-injection after upgrade or install
If there's an onInstalled event handler in background script, what happens with that event handler when chrome updates extension (is this event handler detached, and when update finishes, the new handler is attached and then executed or some other flow is exercised)?
Since an update can only happen while the background page is unloaded, there is no complex logic; it will simply fire on first load of the extension afterwards with details.reason == "update". Be sure to register the handler synchronously on script load (e.g. in top level code), or else you may miss the event — normally this only concerns Event pages, but I suspect it's also important here.
Is there a way to simulate update process during development in order to debug events that happen during the update process, for example to host extension on some local server and update from there?
Sadly, this is no longer possible to the best of my knowledge, unless you can use Enterprise Policy install. Your best bet is to have an extension in CWS that's published as Private.
To a certain extent, pressing "Reload" after making some changes to an unpacked extension simulates what happens during the update - with the exception of onInstalled event.
Where to search for documentation on topics like this and similar, is the chromium source code the right place or at least the starting point?
Well.. For detailed questions Chromium code is, of course, the authoritative source. You should search StackOverflow as well, as there's quite a body of knowledge amassed here already. Finally, the official docs provide a lot of information, even if it's not immediately evident - the chrome.runtime API docs, for example.

Mobile Safari - are there limits in place to prevent large data consumption on first page load?

I have a webapp, that when loaded for the first time has a long initialization sequence. Basically it calls an external API to get loads of data which it caches upon completion, using HTML5 localstorage API.
The issue is, it never gets through initialization in Mobile Safari on the first attempt. At around the same point each time, my AJAX calls just stop firing. When I refresh the page, it starts initialization over again, but this time gets through.
If I clear the browser cache and start this process over again, it is always the same. Fail on first attempt, succeed on subsequent refreshes.
I'm aware that there are certain barriers in place in Mobile Safari to prevent large consumption of data unless in direct response to user input (such as the HTML5 audio tag not being able to 'autoplay').
I'm wondering if there is something similar in place for loading web pages for the first time that immediately consume large amounts of data. And by refreshing, Mobile Safari takes that as your explicit permission to do so.
Anyone know?
I suggest you start with a simple, quick-loading base html file, which will give your user something to look at right away -- even if it's just a simple "Loading...".
Then use ajax to get your "loads of data," using window.onload for example. Ideally give your user something to read or interact with so they don't notice the wait, or a progress indicator, to know the site is actually working.
People are impatient, and when faced with a blank screen and the browser loading indicator not making progress, they're going to assume your site is broken within a few seconds.
The certain barriers...to prevent large consumption of data are probably there for exactly this reason, to improve user experience and prevent monstrous web pages.

Communicating between different windows on the same domain [duplicate]

This question already has answers here:
Communication between tabs or windows
(9 answers)
Closed 6 years ago.
I am building an app that performs a lot of client side data downloading and processing. The data processing is isolated from the main app by being processed in an iframe that resides on a sub domain. It is this iframe that downloads the data. Communication is via postMessage.
Everything works fine, except it could be better.
If the user opens extra tabs/windows, the app currently reloads all the data and may even do duplicate processing work, which isn't a problem other than that it slows everything down and pages take longer to load.
What I would like to do is have each top level tab/window communicate with just the one processing iframe, which could be reinstated if the original window is closed. The trouble is, these are not opened via javascript, but via the normal browser methods to open links in tabs so I can't get a reference to the iframe that is needed to send a message.
Is there anyway I can communicate the window reference for the iframe to the other tabs so that they can communicate with it via a postMessage? Could this in someway be achieved using shared workers?
I realize I could use shared workers for the whole processing task, but this would have it's own problems as the the data comes from third party domains, which can't be accessed from within a worker.
Only compatibility with the latest versions of all major browsers is needed.
Edit: I've just discovered that SharedWorker is not yet implemented in firefox, so I guess that is not going to work. Any other way I could achieve this?
Edit 2: I've discovered that you can use :
var win = window.open('', 'my_window_name');
to capture a reference to an iframe from any other window. However, if the iframe does not already exist then it will open it as a window. Even if it is closed immediately, it causes a flicker and causes the 'popup blocked' messages, making it unusable.
In case any one else finds this, I've come up with a solution. It is somewhat hacky and requires further testing. But so far it is working. It works cross domain if that is needed.
It uses a combination of two tricks.
The first is to use
remote_window = window.open("", "remote_window_name");
to fetch a reference to the window. This works because if a window is already open with the given name then a reference is returned to it rather than opening a new window.
It does however have the problem that if the iframe does not exist then a new window will pop up. Local storage is used in order to prevent this. When a window/tab loads, it checks localStorage to see if there is another page already with a shared iframe. If not it inserts the the iframe and sets a flag in local storage to say that it is available.
As a last ditched resort, if the window still opens, a try block is used to close the newly opened window. The try block prevents cross domain errors. This means that the worst that will happen is the user sees a window pop up and disappear or they will see the 'enable pop-ups' message. I've yet to manage to trigger this in testing - it is only an edge case fall back.
try {
if(store_window.location.href === "about:blank" ){
remote_window.close();
remote_window = insertIfame();
}
} catch(err) {
}
An onunload event is added which removes the flag should the page be closed.
Also a setInterval is created that constantly refreshes a timeout flag. I have it running 4 times a second; when a second window/tab is loaded it checks that the iframe flag has not timed out before trying to communicate with it. This is a small overhead, but far less than the cost to me of having that second iframe loading. This serves the purpose of preventing stale data if the browser crashes or the the onunload does not fire for any reason. I include a small leeway when checking the timeout - currently 1 second - in case the main window is stuck in a loop. The leeway is only on the timeout, not the unload event which removes the flag entirely.
The flag needs to be checked every time a message is sent in case the original window with the iframe has closed. When this happens the iframe is reinserted in the first open window that requires it and the flag is reset.
Sending messages back is easy. Just use the event.source property of the receiveMessage -this points to the sending window.
One final edge case to account for is if the primary window closes whilst it's iframe is mid process for a secondary window. Theoretically this could be dealt with by using an onunload event in the iframe to send a message back to any windows with data in process. But I've yet to implement it and it may not finish before the page unloads. Another way of dealing with it would be by having a timeout in the secondary window which checks the flag and retries, I'll probably go this route as the messages already have timeouts attached.

Categories

Resources