Skip to content

Instantly share code, notes, and snippets.

@3ZsForInsomnia
Last active February 12, 2018 20:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 3ZsForInsomnia/e6bd24076063d8cabc0d70703fcfda6f to your computer and use it in GitHub Desktop.
Save 3ZsForInsomnia/e6bd24076063d8cabc0d70703fcfda6f to your computer and use it in GitHub Desktop.
Quick, ES5-based method for detecting when a page has (probably) fully loaded without relying on the "onload" event
/*
* Explanation of approach
* Check if an element exists with the tag, class, or id of "loading"
* Wait half of interval for things to load/setup/render
* If a "loading" element was found, check if it is visible every time the interval fires
* If the targeted element is not visible when checked, assume loading is complete
* If the targeted element is visible but is changed after the initial timeout, assume that loading is complete
* If no "loading" element is found, then watch <body> for changes
* This causes us to check for when <body> has not been modified for 3 seconds
* While this does add performance overhead (it is called every time <body> or any element below it is modified,
* this is a relatively small amount of work relative to actually changing the DOM itself
*/
var checkLoadingStatus = function() {
var lastCheckedTime = new Date().getTime();
var targetMutationObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
lastCheckedTime = new Date().getTime();
});
});
var selectors = "#loading, loading, .loading";
var target = document.querySelector(selectors);
// Wait a short initial timeout to let things "settle" on the page before trying to determine if loading is complete
setTimeout(() => {
if (target) {
// Check the DOM every "visibilityCheckInterval" milliseconds
var interval = setInterval(() => {
// If there was a loading element, and it is *not* visible
if (!isLoadingElementVisible(target)) {
methodCalledWhenLoadingIsComplete(
interval,
targetMutationObserver
);
} else {
// If there was a loading element and it is still visible
var currentTimeWithExistingTarget = new Date().getTime();
// If the loading element is still visible but has not changed in 3 seconds, assume loading is complete or is nearly complete
if (currentTimeWithExistingTarget > lastCheckedTime + 3000) {
methodCalledWhenLoadingIsComplete(
interval,
targetMutationObserver
);
}
}
}, 1000);
targetMutationObserver.observe(target, {
attributes: true,
childList: true,
subtree: true
});
} else {
targetMutationObserver.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
var interval = setInterval(() => {
var currentTime = new Date().getTime();
if (currentTime > lastCheckedTime + 3000) {
methodCalledWhenLoadingIsComplete(
null,
targetMutationObserver
);
}
}, 1000);
}
}, 500);
};
var methodCalledWhenLoadingIsComplete = function(interval, observer) {
if (interval) clearInterval(interval);
observer.disconnect();
console.log("ready!");
};
var isLoadingElementVisible = function(target) {
var rectangle = target.getBoundingClientRect();
var page = document.documentElement;
return (
rectangle.top > 0 &&
rectangle.left > 0 &&
rectangle.bottom < (window.innerHeight || page.clientHeight) &&
rectangle.right < (window.innerWidth || page.clientWidth)
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment