AprilSylph / XKit-Rewritten

🧰 The enhancement suite for Tumblr's new web interface
GNU General Public License v3.0
274 stars 44 forks source link

MV3 branch: Stop processing disconnected elements #1500

Closed marcustyphoon closed 6 days ago

marcustyphoon commented 1 week ago

Asynchronous inject can result in race conditions where there were previously not any. (Well, maybe this isn't what you would think of of as a race condition? Anyway, by the time the code runs, the target may not be attached to the DOM any more, e.g. if you've scrolled past it.)

Presuming we don't want to pursue instant injection, at least at the moment, this should be fairly easy to handle. I would probably just decline to run unburyTimelineObject and never resolve the inject promise, at first thought? That would stall the function awaiting the inject forever rather than making it have to put a conditional on the result. Not sure how garbage collection works in that case, though; we don't want to leave DOM elements un-GC'd because they have event listeners pending.

_Originally posted by @marcustyphoon in https://github.com/AprilSylph/XKit-Rewritten/pull/1466#discussion_r1616413489_

Description

One way to prevent the console being filled with errors whenever you scroll any timeline with the current MV3 branch, without needing to adjust every location we call timelineObject(), is to respond to injection requests for no-longer-attached-by-the-time-we-process elements with a promise that is neither resolved nor rejected. One would otherwise have to add a conditional early return to each invocation of the function.

This diff is... really not great, but I don't really have an idea of how to do it that's more elegant. A shorter diff would just be if (document.currentScript.isConnected) return; atop each injected function, but that results in a proliferation of mutation observers.

Actually... maybe the observer gets GC'd with the element it's on? Eh that could be good enough tbh.

Testing steps