1. необходимо еще на всякий случай устанавливать обычный load для древних браузеров, которые совсем тупые. Я имею в виду не вручную это делать, а скрипт сам должен учитывать это. Во втором способе это делается, но через жопу, а надо через addEventListener и attachEvent.
2. кусок
if (/WebKit/i.test(navigator.userAgent)) {
safariTimeout = setInterval(function(){if (/loaded|complete/.test(d.readyState)) {clearInterval(safariTimeout); t.runHandlers() }}, 100);
написан для safari2, который давно умер (да и не пользовался им никто под windows, слишком глючный был). Т. е. его (safari2) можно (даже нужно, зачем поддерживать лишний код из-за 0.00....01% посетителей) отнести к "остальным" браузерам, для которых делается обычный load (пункт 1). А в safari3 отлично работает DOMContentLoaded.
3. способ с defer появился раньше, чем с doScroll. Сейчас почти все известные фреймворки перешли на doScroll, наверное, он чем-то лучше, но я как не тестировал defer, так и не смог понять чем он плох, все отлично работает, и так как я понимаю этот способ лучше, то использую именно его.
4. в обоих вариантах есть моменты, которые теоретически могут привести к memory leak.
Мой вариант (все добавленные события удаляются, ссылка на созданный элемент script не попадает ни в какие замыкания, script.onreadystatechange обнуляется, сам элемент script удаляется из dom, в общем, все аккуратно и полностью чистится, никаких memory leak):
$.isReady = false;
$.ready = (function() {
var handlers = [], load = function() {
if ($.isReady) return;
$.isReady = true;
$d.removeEventListener && $d.removeEventListener('DOMContentLoaded', load, false);
if (IE) {
var script = $d.getElementById('_defered');
if (script) {
script.onreadystatechange = null;
Element.remove(script);
}
}
Event.remove($w, 'load', load);
var i = 0, length = handlers.length;
while (i < length) handlers[i++].call($d);
handlers.length = 0;
};
$d.addEventListener && $d.addEventListener('DOMContentLoaded', load, false);
if (IE) {
$d.write('<script type="text/javascript" src="javascript:void(0);" id="_defered" defer="defer"><\/script>');
$d.getElementById('_defered').onreadystatechange = function() {
this.readyState == 'complete' && load();
};
}
Event.add($w, 'load', load);
return function(handler) {
$.isReady ? handler.call($d) : handlers.push(handler);
return $;
};
})();