

Faster than jQuery(document).ready() - Wait Until Exists - dous
http://javascriptisawesome.blogspot.nl/2011/07/faster-than-jquerydocumentready-wait.html

======
Vekz
Good Idea. Unfortunately the underlying technique the author has used to
achieve this (DOM mutation events) is flawed, deprecated and non-optimal.

<https://developer.mozilla.org/en-US/docs/DOM/Mutation_events>

"Adding DOM mutation listeners to a document profoundly degrades the
performance of further DOM modifications to that document (making them 1.5 - 7
times slower!). Moreover, removing the listeners does not reverse the damage."

Using the modern DOM mutation observers may be a better solution.

~~~
andrethegiant
Came here to say this.

[http://updates.html5rocks.com/2012/02/Detect-DOM-changes-
wit...](http://updates.html5rocks.com/2012/02/Detect-DOM-changes-with-
Mutation-Observers)

------
jacobr
What people need to stop doing is to wrap their entire application in
$(doc).ready().

Just as an example, you can initialize your Backbone Models and start sending
out XHR's without worrying about the DOM.

------
kwamenum86
Don't use this. Mutation events are insanely expensive.

------
mistercow
This is very cool, and would definitely be useful whenever you don't need to
know much about layout or overall page state before your code starts running.
Here's some feedback:

I worry about the idea of waiting until late-appearing elements show up if
you're selecting on the id. It's tricky to use that feature correctly because
ids are globally unique. To handle ids sanely in flexible code, you have to
automatically generate them (using, say underscore's uniqueId). Then you pass
them around so your code is all talking about the same element. Yuck. At that
point, we might as well pass around callbacks.

So you could solve most of that if you let waitUntilExists work for class
selectors too. Then the user would just refer to it by the context, passing
"itself" as the last parameter.

Which brings me to my last point of feedback: why "itself"? Seems to me that
it would make more sense to just have the element be the default context if no
last parameter is provided (or if it's undefined).

------
jdavid
If you don't wait for the DOM to load, it really can make it hard to alter
parts of it, and it can cause odd problems that are hard to debug because it
creates timing inconsistencies.

I'd much rather see a small DOM, so the ready event can fire quickly than do
something like this.

For an extension I wrote which adds interface elements to the Facebook
timeline, I needed a custom solution to monitor when parts of the dom were
changing, since facebook implements infinite scroll. In this case I couldn't
use mutation even if I wanted to because of the scoping of chrome extensions.

Since the facebook implementation does a lot of work to render infinite scroll
quickly i needed something fast, and lightweight. for this i choose a pattern
that locates new dom elements on an interval, appends a class, and then
triggers a new event, which then looks for that class ( which is indexed by
the browser ) and then does a foreach on each of those new elements only.

I found setting the interval to 100ms was a good fit on facebook, as it's
generally the amount of time that a user will take to notice a change. I could
have set it lower, to 50ms, 20ms, or even lower, but i found that it caused
too much blocking. in many cases the DOM and javascript both need access to
the threads and if you have intervals running on too small of an interval,
like 5 seconds in this library you are likely going to block the dom from
rendering quickly. also, it's unlikely that the browser will actually fire
something at 5ms precision.

if you are going to follow a pattern like this i would advise you to use
something in the 25ms+ range for your interval and also make sure that your
interval script does not cause an invalidation on your browser elements. on a
second async call you can then safely alter each element which should assure
that you don't have any blocking behaviors.

------
moonboots
A simpler method is adding a blocking script tag immediately below the DOM
element.

~~~
mistercow
That's a synchronous solution though, and it doesn't let you do the more
advanced use case where you wait for a div to load long after document ready.

------
mmuro
.ready() is actually pretty smart and a lot faster than most people give it
credit for.

~~~
pablasso
care to elaborate a little bit?

~~~
lars
I don't know that it's all that smart. It uses the DOMReady event in all
modern browsers, and uses a load of tricks to get the same behaviour in older
browsers. It will never fire before the DOM is ready, like the function in the
article does.

~~~
mmuro
If you don't want to wait for the DOMReady event, you can always write it like
so:

(function($) { // $() will work as an alias for jQuery() inside of this
function })(jQuery);

------
darklajid
Previously: <http://news.ycombinator.com/item?id=2801835>

------
2bit
Same functionality but for YUI: <http://yuilibrary.com/gallery/show/event-
inserted>

Uses CSS3 Animation if available, otherwise falls back to DOMNodeInserted.

------
awschmitz
Or you could use the built-in setInterval() function to poll for the DOM
element and not have to worry about attaching an event handler to a deprecated
event. It's expensive, but will only happen in between the time that this code
is interpreted and the DOM element loads. And you could easily write something
to check for timeout in case is takes too long.

var intID = setInterval(function() { if($("myDOMElement").length ||
checkForTimeOut()) { clearInterval(intID); doSomething(); } }, 100);

...if it starts lagging just increase the interval time (that last integer).

------
chucknibbleston
I bet that setting an interval to check for the specific node is actually more
performant than using the mutation event (which as @Vekz pointed out, slows
down the whole DOM)...

