Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 09.11.2009, 15:53
Аватар для HelpeR
Профессор
Отправить личное сообщение для HelpeR Посмотреть профиль Найти все сообщения от HelpeR
 
Регистрация: 21.10.2008
Сообщений: 241

DOMContentLoaded и defer
Искал в сети как отловить событие загрузки DOM.
Нашел следующий два скрипта
1. Это я вырезал из js кода одноклассников
var d = document, t = this, safariTimeout;
		if (/WebKit/i.test(navigator.userAgent)) {
			safariTimeout = setInterval(function(){if (/loaded|complete/.test(d.readyState)) {clearInterval(safariTimeout); t.runHandlers() }}, 100);
		} else if (d.addEventListener) {
			d.addEventListener("DOMContentLoaded", function(){t.runHandlers()}, false);
		} else if (d.all && !window.opera) {
			var s = d.createElement("script");
			s.setAttribute("type", "text/javascript");
			s.setAttribute("src", "");			
			s.setAttribute("defer", "true");
		 	s.onreadystatechange = function(){if (this.readyState == "complete") t.runHandlers()} 
			this.h.insertBefore(s, this.h.firstChild); 
		}

и второй
(function(i) {
		  var u = navigator.userAgent;
		  var e=/*@cc_on!@*/false; 
		  var st = setTimeout;

		  if(/webkit/i.test(u)){
			  st(function(){
						  var dr=document.readyState;
						  if(dr=="loaded"||dr=="complete"){
							  i()
						  }
						  else{
							  st(arguments.callee,10);
						  }
			  },10);
		  }
		  else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
			  document.addEventListener("DOMContentLoaded",i,false); 
		  }
		  else if(e){
			  (function(){
						var t=document.createElement('doc:rdy');
						try{
							t.doScroll('left');
						    i();
						    t=null;
						 }
						 catch(e){
							 st(arguments.callee,0);
						  }
				   })();
			  }
			  else{
				  window.onload=i;
			  }
		})(init);
где init это название вызываемой функции при загрузке DOM. В коде одноклассников все ясно, а как тут реализовали проверку в ИЕ? и еще вопрос, всегда ли корректно работает аттрибут defer? И можете чуть подробнее пояснить, что сделали в однок. для ИЕ?
Заранее спасибо!
Ответить с цитированием
  #2 (permalink)  
Старый 09.11.2009, 20:17
Профессор
Отправить личное сообщение для alexKniaz Посмотреть профиль Найти все сообщения от alexKniaz
 
Регистрация: 14.10.2008
Сообщений: 186

По-моемк код в try вызывает в ie ошибку и выполняется catch
__________________
http://alexcoder.ucoz.ru - мой начинающийся сайт
Ответить с цитированием
  #3 (permalink)  
Старый 10.11.2009, 08:56
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

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 $;
};

})();

Последний раз редактировалось Riim, 10.11.2009 в 09:15.
Ответить с цитированием
  #4 (permalink)  
Старый 10.11.2009, 09:53
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Сообщение от Riim
Сейчас почти все известные фреймворки перешли на doScroll, наверное, он чем-то лучше, но я как не тестировал defer, так и не смог понять чем он плох, все отлично работает, и так как я понимаю этот способ лучше, то использую именно его.
Для возможности неблокирующей загрузки скрипта избавляются от document.write('<script … defer …>').
Ответить с цитированием
  #5 (permalink)  
Старый 10.11.2009, 10:01
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

Octane, можно чуть подробней?
Ответить с цитированием
  #6 (permalink)  
Старый 10.11.2009, 11:14
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Чтобы сделать возможным загрузку скрипта с фреймворком, как будто у него атрибут defer установлен. Для оптимизации скорости загрузки страницы используют. Ну или, чтобы использовать вот такую модную штуку: http://code.google.com/intl/ru/apis/ajaxlibs/

Последний раз редактировалось Octane, 10.11.2009 в 11:20.
Ответить с цитированием
  #7 (permalink)  
Старый 16.11.2009, 11:04
Аватар для HelpeR
Профессор
Отправить личное сообщение для HelpeR Посмотреть профиль Найти все сообщения от HelpeR
 
Регистрация: 21.10.2008
Сообщений: 241

Riim,
Спасибо, что подсказали на счет удаления событий.
Octane,
А способ использующий в одноклассниках тоже блокирующий загрузку скрипта? или insertBefore не работает как doScroll ?
Ответить с цитированием
  #8 (permalink)  
Старый 16.11.2009, 11:06
Аватар для HelpeR
Профессор
Отправить личное сообщение для HelpeR Посмотреть профиль Найти все сообщения от HelpeR
 
Регистрация: 21.10.2008
Сообщений: 241

и можно было бы по подробнее объяснить вот этот кусок кода
var t=document.createElement('doc:rdy');
                        try{
                            t.doScroll('left');
                            i();
                            t=null;
                         }
                         catch(e){
                             st(arguments.callee,0);
                          }
что это за элемент и как к нему относится doScroll
Ответить с цитированием
  #9 (permalink)  
Старый 16.11.2009, 15:26
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Сообщение от HelpeR
Octane,
А способ использующий в одноклассниках тоже блокирующий загрузку скрипта? или insertBefore не работает как doScroll ?
Не знаю, что там в одноклассниках, там все на GWT написано, страшно заглядывать.

Сообщение от HelpeR
блокирующий загрузку скрипта?
Скрипт блокирует загрузку:
<script type="text/javascript">var a = 1</script>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">alert(a); // 2</script>

script.js
a = 2


А при неблокирующей загрузке:
<script type="text/javascript">var a = 1</script>
<script type="text/javascript" defer="defer" src="script.js"></script>
<script type="text/javascript">alert(a); // 1</script>

script.js
a = 2


Кстати, defer поддерживает не только IE, но и новые версии Firefox.

Сообщение от Octane
и можно было бы по подробнее объяснить вот этот кусок кода
В IE попытка использовать метод doScroll до загрузки документа приводит к ошибке, вот и повторяем попытки, пока ошибка не исчезнет. Элемент doc:rdy не знаю зачем написали, по идее, для любого элемента должно работать.
Ответить с цитированием
  #10 (permalink)  
Старый 16.11.2009, 15:36
Аватар для HelpeR
Профессор
Отправить личное сообщение для HelpeR Посмотреть профиль Найти все сообщения от HelpeR
 
Регистрация: 21.10.2008
Сообщений: 241

Octane,
Спасибо большое за ответ!
Ответить с цитированием
Ответ


Опции темы Искать в теме
Искать в теме:

Расширенный поиск