Page Lifecycle
Document / Resource Loading: Page Lifecycle
What is the Page Lifecycle API?
View Answer:
What are the three crucial events in the lifecycle of an HTML page?
View Answer:
The three crucial events in the lifecycle of an HTML page are:
Loading the HTML: This occurs when the browser requests the page from the server. The server then sends the HTML content to the browser.
DOMContentLoaded: This event occurs when the browser finishes parsing the HTML of the page, creating the Document Object Model (DOM).
Load: This event is fired when the page has been fully loaded, including all scripts, stylesheets, images, and other resources.
Here is a simple JavaScript example that demonstrates these three events:
<!DOCTYPE html>
<html>
<head>
<title>Page Lifecycle Events</title>
<style>
body {
font-family: Arial, sans-serif;
}
</style>
<script>
document.onreadystatechange = function () {
if (document.readyState === "interactive") {
console.log("HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.");
}
else if (document.readyState === "complete") {
console.log("The page and all related resources such as stylesheets and images have been completely loaded.");
}
}
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM fully loaded and parsed");
});
window.addEventListener("load", function() {
console.log("All resources have finished loading!");
});
</script>
</head>
<body>
<h1>Welcome to my website!</h1>
<img src="example.jpg" alt="Example image">
</body>
</html>
Output:
"HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading."
"DOM fully loaded and parsed"
"The page and all related resources such as stylesheets and images have been completely loaded."
"All resources have finished loading!"
In this example, the readystatechange
event listener is used to detect the interactive and complete states, which correspond to the HTML loading event and the Load event, respectively. The DOMContentLoaded
event listener is used to detect when the DOM is fully loaded and parsed.
Note that the window.onload
event won't fire until all resources (e.g., images, stylesheets) have finished loading, not just the DOM.
How are the DOMContentLoaded, load, beforeunload/unload events useful?
View Answer:
What does the "loading" state signify?
View Answer:
if (document.readyState === "loading") { // Checking if document is still loading
console.log("The document is currently loading.");
} else {
console.log("The document has finished loading.");
}
This code logs a message to the console based on whether the document is still loading or has finished loading. The readyState
property of the document
object is used to get the current loading state of the document.
When does the "interactive" stage occur in HTML?
View Answer:
document.onreadystatechange = function () {
if (document.readyState === "interactive") {
console.log("The document has been fully read and parsed, sub-resources are still loading.");
}
}
In this code, an event listener is set on document.onreadystatechange
to log a message when the readyState
property of the document object becomes "interactive", indicating that the HTML has been parsed but some resources may still be loading.
What happens during the "interactive" stage in an HTML Document?
View Answer:
What does the "complete" stage represent?
View Answer:
document.onreadystatechange = function () {
if (document.readyState === "complete") {
console.log("The entire page, including all dependent resources, has been fully loaded and rendered.");
}
}
In this code, an event listener is set on document.onreadystatechange
to log a message when the readyState
property of the document object becomes "complete", indicating that all resources including images, stylesheets, and scripts are fully loaded and rendered.
How can you listen for the page load event in JavaScript?
View Answer:
Here is a JavaScript code example that listens for the page load event:
window.addEventListener('load', function() {
console.log('The page has fully loaded');
});
In this example, we're using addEventListener
on the window
object to listen for the load
event, which is fired when the entire page loads, including its content (images, CSS, scripts, etc.). When this event fires, it logs a message to the console.
How can you listen for the DOMContentLoaded event?
View Answer:
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM fully loaded and parsed');
});
In this example, addEventListener
is used on the document
object to listen for the DOMContentLoaded
event, which is fired when the initial HTML document has been completely loaded and parsed, but sub-resources like stylesheets, images, and scripts may not have finished loading. When this event fires, it logs a message to the console.
On what object does the DOMContentLoaded event occur?
View Answer:
<script>
function ready() {
console.log('DOM is ready');
// image is not yet loaded (unless it was cached), so the size is 0x0
console.log(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
}
document.addEventListener('DOMContentLoaded', ready);
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0" />
We should note a few peculiarities when we try to solicit information before the page is completely loaded, like image sizes, and the DOM loads first and then images and styles.
What happens when the browser processes a document and comes across a '<script>' tag?
View Answer:
<!DOCTYPE html>
<html>
<head>
<title>Script Processing</title>
</head>
<body>
<p id="p1">Hello</p>
<script>
// This will execute immediately, updating the text from "Hello" to "Hello, World!"
document.getElementById("p1").innerHTML += ", World!";
</script>
<p id="p2">Goodbye</p>
<script>
// This will execute immediately after the previous script, updating the text from "Goodbye" to "Goodbye, World!"
document.getElementById("p2").innerHTML += ", World!";
</script>
</body>
</html>
In this example, when the browser encounters the first <script>
tag, it stops parsing the HTML, executes the JavaScript that modifies the text of the first paragraph, then resumes parsing. The same happens when it encounters the second <script>
tag.
Are there any exceptions to script blocking of the DOMContentLoaded event?
View Answer:
Here is an example demonstrating this:
<!DOCTYPE html>
<html>
<head>
<title>Async and Defer</title>
<script src="script.js" async></script> <!-- This script doesn't block parsing -->
</head>
<body>
<script src="script2.js" defer></script> <!-- This script doesn't block parsing -->
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM fully loaded and parsed");
});
</script>
</body>
</html>
In this example, the async
and defer
scripts will not block the DOMContentLoaded event. The DOMContentLoaded event will fire as soon as the document is fully parsed, even if these scripts haven't finished loading or executing.
Do external style sheets influence or affect the DOM?
View Answer:
<link type="text/css" rel="stylesheet" href="style.css" />
<script>
// the script doesn't not execute until the stylesheet is loaded
console.log(getComputedStyle(document.body).marginTop);
</script>
How does the built-in browser autofill interact with the DOMContentLoaded event?
View Answer:
<!DOCTYPE html>
<html>
<head>
<title>Autofill Interaction</title>
</head>
<body>
<form>
<label for="name">Name:</label>
<input type="text" id="name" name="name" autocomplete="name">
<label for="email">Email:</label>
<input type="text" id="email" name="email" autocomplete="email">
<input type="submit" value="Submit">
</form>
<script>
document.addEventListener("DOMContentLoaded", function() {
setTimeout(function() { // Timeout for autofill to occur
let nameField = document.getElementById('name');
let emailField = document.getElementById('email');
console.log(`Name: ${nameField.value}`);
console.log(`Email: ${emailField.value}`);
}, 200);
});
</script>
</body>
</html>
In this example, the script listens for the DOMContentLoaded
event. Then, it waits a bit for the browser to autofill the form fields (if applicable), and finally logs the values of the name and email fields. The autocomplete
attributes are set to help the browser know what type of information should be autofilled.
Can you explain how the load event behaves via the onload property?
View Answer:
<script>
window.onload = function () {
// same as window.addEventListener('load', (event) => {
console.log('Page loaded');
// image is loaded at this time
console.log(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
};
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0" />
What event is triggered when a user leaves the browser page?
View Answer:
<!DOCTYPE html>
<html>
<head>
<title>Page Exit Events</title>
<script>
window.addEventListener("beforeunload", function (event) {
// Cancel the event and show a confirmation dialog
event.preventDefault();
event.returnValue = "Do you really want to leave?";
});
window.addEventListener("unload", function (event) {
console.log("Page is being unloaded.");
});
</script>
</head>
<body>
<h1>Try leaving this page</h1>
</body>
</html>
In this example, if a user tries to close the tab, refresh the page, or navigate away, they'll see a confirmation dialog due to the beforeunload
event. The unload
event also triggers, but you won't see the console log because the page is already unloading. It's mostly used to clean up things like event listeners and running timers.
Is there a reason we should avoid using unload and beforeunload in conjunction with Navigator.sendBeacon method?
View Answer:
Sure, here's an example that demonstrates using visibilitychange
and pagehide
events with navigator.sendBeacon()
method:
window.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon("/log", "User left the page");
}
});
window.addEventListener('pagehide', function() {
navigator.sendBeacon("/log", "Page is being unloaded");
});
In some modern browsers like Safari, unload
and beforeunload
events don't guarantee the execution of asynchronous requests like sendBeacon()
. Instead, visibilitychange
and pagehide
events provide a more reliable way to ensure the request is made.
It's best to avoid making complex operations, like AJAX requests, inside unload
or beforeunload
events. However, Navigator.sendBeacon()
is specifically designed to be used in these situations where a normal AJAX request might be cancelled because the page is unloading.
What happens if we set the DOMContentLoaded handler after the document is loaded?
View Answer:
<!DOCTYPE html>
<html>
<head>
<title>DOMContentLoaded Handler</title>
<script>
// This event handler will run because it's registered before the DOMContentLoaded event fires
document.addEventListener("DOMContentLoaded", function() {
console.log("This will log when the DOM is fully loaded.");
});
</script>
</head>
<body>
<h1>Welcome to my website!</h1>
<script>
// This event handler won't run because it's registered after the DOMContentLoaded event has already fired
document.addEventListener("DOMContentLoaded", function() {
console.log("This won't log because the DOM is already loaded.");
});
</script>
</body>
</html>
In this example, the first DOMContentLoaded
event handler logs a message to the console because it's registered before the event fires. The second handler, registered after the event fires, won't log its message because it missed the event.
Is there a way to find the document loading state?
View Answer:
Syntax: let string = document.readyState;
<!DOCTYPE html>
<html>
<head>
<title>Document Loading State</title>
</head>
<body>
<h1>My Web Page</h1>
<img src="example.jpg" alt="Example image">
<script>
document.onreadystatechange = function () {
console.log("Document state: " + document.readyState);
if (document.readyState === "interactive") {
console.log("Document has been fully read.");
}
else if (document.readyState === "complete") {
console.log("Document and all sub-resources are now fully loaded.");
}
}
</script>
</body>
</html>
In this example, an onreadystatechange
event handler is registered, and it logs the current state of the document to the console each time the state changes. When the state changes to "interactive"
, it logs a message stating that the document has been fully read, and when it changes to "complete"
, it logs a message stating that the document and all sub-resources are fully loaded.
What are the three possible values of the readyState?
View Answer:
Syntax: let string = document.readyState;
There are three possible values:
"loading"
: The document is still loading."interactive"
: The document has been fully read."complete"
: The document and all sub-resources have been fully loaded.
Here's an example:
function work() {
/*...*/
}
if (document.readyState == 'loading') {
// still loading, wait for the event
document.addEventListener('DOMContentLoaded', work);
} else {
// DOM is ready!
work();
}
How can you prevent the page from being unloaded?
View Answer:
window.addEventListener('beforeunload', function (event) {
// Cancel the event and show a dialog prompt
event.preventDefault();
// Chrome requires returnValue to be set
event.returnValue = '';
});
In this code, an event listener is attached to the beforeunload
event. When the event is fired, which is right before the window is about to be unloaded, it prevents the default action and sets event.returnValue
to an empty string, which may prompt the user to confirm they really want to leave. Note that this behavior may vary between browsers, and some may not support it at all for user experience reasons.
What is the purpose of the Page Visibility API?
View Answer:
How can you listen for changes in the page visibility state?
View Answer:
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'visible') {
console.log('Page is now visible');
} else {
console.log('Page is now hidden');
}
});
In this example, we're using addEventListener
on the document
object to listen for the visibilitychange
event. The callback function checks the document.visibilityState
property and logs a message depending on whether the page is visible or not.
What are the possible visibility states?
View Answer:
How can you pause/resume expensive operations when the page is not visible?
View Answer:
Sure, here is a JavaScript code snippet that pauses and resumes an operation based on the visibility of the page:
let expensiveOperation = function() {
// Simulating an expensive operation
console.log("Running expensive operation");
};
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
clearInterval(intervalId); // Pausing operation
console.log("Paused expensive operation");
} else {
intervalId = setInterval(expensiveOperation, 1000); // Resuming operation
console.log("Resumed expensive operation");
}
});
let intervalId = setInterval(expensiveOperation, 1000); // Start operation
In this code, expensiveOperation
is a function that represents an operation that uses a lot of resources. When the page visibility changes (as detected by the visibilitychange
event), it checks if the page is hidden and if so, it pauses the operation by clearing the interval. If the page becomes visible again, it resumes the operation by starting the interval again.
What is the purpose of the Navigation Timing API?
View Answer:
window.addEventListener('load', function() {
setTimeout(function() {
var performance = window.performance;
if(performance) {
var timing = performance.timing;
var loadTime = timing.loadEventEnd - timing.navigationStart;
console.log('Page load time is ' + loadTime + ' milliseconds.');
}
}, 0);
});
In this example, once the window's load
event has fired, it gets the window.performance
object, which contains timing-related information. Specifically, it calculates the total time taken to load the page (from the start of navigation to when the load
event ends) and logs it to the console.
What is the Performance Timing API?
View Answer:
How can you access the performance timing information?
View Answer:
What is the purpose of the Resource Timing API?
View Answer:
How can you access the resource timing information?
View Answer:
Here's a JavaScript code example that uses the Resource Timing API to get some timing-related metrics for a specific resource:
window.addEventListener('load', function() {
var resourceList = window.performance.getEntriesByType("resource");
for (let i = 0; i < resourceList.length; i++) {
if (resourceList[i].name === "http://example.com/my-resource.jpg") {
console.log("Duration of my-resource.jpg: " + resourceList[i].duration);
console.log("Response time of my-resource.jpg: " + resourceList[i].responseEnd);
}
}
});
In this example, once the window's load
event has fired, it gets a list of all resource timings using window.performance.getEntriesByType("resource")
. It then goes through this list and for a specific resource (in this case, "http://example.com/my-resource.jpg"), it logs the total duration of the request and the time at which the final byte of the response was received.
What is the purpose of the Beacon API?
View Answer:
How can you use the Beacon API to send data?
View Answer:
Here's a JavaScript code example that uses the Beacon API to send data:
// Data to send
let data = {
event: 'button click',
time: new Date().getTime()
};
// Convert the data to JSON
let jsonData = JSON.stringify(data);
// Send the data
navigator.sendBeacon('https://example.com/collect-data', jsonData);
In this example, we first create a data object that represents some data we want to send. We then convert this data to JSON using JSON.stringify()
. Finally, we send the data to a server using navigator.sendBeacon()
. The sendBeacon()
method returns true
if the user agent is able to successfully queue the data for transfer, false
otherwise.