Update
There's a better way, the one below should work, but this one should be safer, still (and it's easier, IMO).
Given that JS is single-threaded, an event will push the handler to the back of the queue anyway, so if your onload
handler ends up being called prior to another handler, dispatching a new event, that calls a handler that actually does the work you want/need to do is probably your best bet:
window.addEventListener('load', function rmMe()
{
var handler = function()
{
window.removeEventListener('click', handler, false);//remove this listener, too
var i, links = document.querySelectorAll('a');
for (i=0;i<links.length;++i)
{
//do stuff with links
}
};
window.removeEventListener('load', rmMe, false);
window.addEventListener('click', handler, false);//bind new listener
window.dispatchEvent(new Event('click'));//calls handler, last handler in queue
},false);
That might be your best bet...
After those endless comments, it would apear that you're looking for a way to guarantee that your JS gets executed after the page has loaded, and all other possible onload
event handlers have been called.
The simple answer is: you can't. Not really. JS's event loop is beyond your control, but there are a few tricks that do work in most cases:
- Add your script to the bottom of the body tag
- Bind your event listener but wrap it in a
setTimeout
with zero or 1 ms delay
- to be safe, let the event handler set another timeout that actually calls the function that does the work, this time, use a timeout that allows for a queued handler to be called. This is optional, because the queue is probably empty already
- important make sure (or hope) that other handlers don't call
stopPropagation
on the event: this'll result in your listener not getting called. That's why the first method is preferable: it pushes a new handler to the back of the queue, allowing you to bind your listener first.
Code example:
setTimeout(function()
{
window.onload = function()
{
var handler = function()
{
var i, links = document.querySelectorAll('a');
for (i=0;i<links.length;++i)
{
//do stuff with links
}
};
return function()
{//fake, initial handler
setTimeout(handler, 40);//optional, return handler; should suffice
};
};
},1);
That's all there is too it. This code, to be clear, goes here in the DOM:
<script>
//code here
</script>
</body>
</html>
This is not 100% reliable, but most browsers queue event handlers as they are being bound:
window.addEventListener('load', function(){}, false);//likely to be called first
window.addEventListener('load', function(){}, false);//likely to be called second
and so on. Not sure about this, but I wouldn't be surprised if listeners that are bound using the window.addEventListener
are more likely to be appended to the end of the queue, as the addEventListener
call may cause overhead. Probably use:
setTimeout(function()
{
window.addEventListener('load', function tmpLoad()
{
var handler = function()
{
var i, links = document.querySelectorAll('a');
for (i=0;i<links.length;++i)
{
//do stuff with links
}
};
return function()
{//fake, initial handler
window.removeEventListener('load', tmpLoad, false);//adds overhead and time
setTimeout(handler, 40);//optional, return handler; should suffice
};
},false);
},1);
You could also consider manually dispatching an event, after a timeout, bind a new listener, and then do: window.dispatchEvent(new Event('load'));
to call the handler.