I had to implement some testing logic recently where I wanted to wait for a heavy page to load and for specific elements to become available. I knew I wanted a function that polled the page and returned true
if it found the element or rejected if it didn’t.
I actually looked some a pre existing solution and turned up a blank. There are code examples out there, but some developers have created some over engineered solutions using things like proxies, mutation observers and other convoluted ways of waiting for elements.
All I wanted to be able to do was call a function which would wait for an element to exist in the page and return true if it was found or error out if it wasn’t.
async function waitForElement(selector: string, attempts: number = 10) {
const query = document.querySelectorAll(selector);
if (query.length) {
return true;
}
setTimeout(() => {
attempts--;
if (attempts > 0) {
return waitForElement(selector, attempts);
}
throw new Error('Element not found');
}, 100);
}
This code is written with TypeScript and is quite easy to follow. We create a new asynchronous function which will return a promise. It accepts a selector which gets passed to querySelectorall
and a second argument which is the number of attempts before it errors out.
The function recursively calls itself until the number of attempts equals 0 and then it throws an error, thus, rejecting the promise. If it finds the element, it returns true.
const elementFound = await waitForElement('#someelement');
Sure, some of the other solutions out there might be more technically impressive, but I’m a realist and more often than not, I go for the solutions that are readable and functional.