Tired of whatever silly color I've picked? Rotate the overall hue by hovering the site title!

Extend MutationObserver replacement with promises

Remember that silly thing I did a couple posts ago to avoid looking for DOM changes properly for no particular reason other than not wanting to deal with the syntax of it? Let's take it another step by adding promises to the mix. If it's a step in the wrong direction but objectively makes it better, is it still wrong?

Probably. As I said before, I recognize the usefulness of MutationObserver, but I do feel like it's overly verbose for some tasks. Thus, I offered up a solution using a not-too-fast setInterval() loop instead. Is it the "correct" solution? No, but if you only have to watch for one thing before moving on, it'll suffice.

In lieu of forcing you to click over into the other post, here's the idea:

// ≈≈ observer.observe()
const spanWatch = setInterval(() => {
    if (document.querySelector('code span')) {
        clearInterval(spanWatch);
        // Do your thing here.
    }
}, 100); // Not too fast!

To add a promise to the mix, let's wrap it in a method we'll put on document.

document.lookFor = function (selector) {
	return new Promise((resolve) => {
		const check = setInterval(() => {
			if (document.querySelector(selector)) {
				clearInterval(check);
				resolve(document.querySelectorAll(selector));
			}
		}, 100);
	});
};

Instead of needing to "do your thing here" within the looped function, we can use it like an asynchronous document.querySelectorAll().

document.lookFor('code span').then((spans) => {
	console.log(spans);
});

When one match is found in the document, all of them are grabbed and our promise revolved, allowing then() to make an appearance with all our now-found elements ready for looping over. Not bad.

But what this really needs to feel complete is to be available on individual elements! Let's pollute HTMLElement.prototype a little so it can be run on elements just like querySelectorAll() can be. I know you're not supposed to mess with class prototypes, but if you have control over your code base and you're careful, is there truly any harm in it? I submit that there is not. Let's extend this even further beyond!

HTMLElement.prototype.lookFor = function (selector) {
	const thisElem = this; // jic
	return new Promise((resolve) => {
		const check = setInterval(() => {
			if (thisElem.querySelector(selector)) {
				clearInterval(check);
				resolve(thisElem.querySelectorAll(selector));
			}
		}, 100);
	});
};

Now we've got asynchronous watchers available on the document and individual elements, and MutationObserver is extremely avoided.

Leave a comment

Your email address will not be published. Required fields are marked *