Last active
February 12, 2018 20:20
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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