Javascript.RU

Кроссбраузерное событие onDOMContentLoaded

Для инициализации страницы исторически использовалось событие window.onload, которое срабатывает после полной загрузки страницы и всех объектов на ней: счетчиков, картинок и т.п.

Событие onDOMContentLoaded - гораздо лучший выбор в 99% случаев. В этой статье рассмотрен код и основные приемы для его кроссбраузерной реализации.

Это событие срабатывает, как только готов DOM документ, до загрузки картинок и других не влияющих на структуру документа объектов.

Это очень удобно, т.к. картинки могут загружаться долго, а обработчик onDOMContentLoaded может произвести необходимые изменения на странице и инициализацию интерфейсов тут же, не дожидаясь загрузки всего.

"Родное" событие onDOMContentLoaded есть не во всех браузерах, поэтому мы рассмотрим код для кроссбраузерной поддержки этого события:

function bindReady(handler){

	var called = false

	function ready() { // (1)
		if (called) return
		called = true
		handler()
	}

	if ( document.addEventListener ) { // (2)
		document.addEventListener( "DOMContentLoaded", function(){
			ready()
		}, false )
	} else if ( document.attachEvent ) {  // (3)

		// (3.1)
		if ( document.documentElement.doScroll && window == window.top ) {
			function tryScroll(){
				if (called) return
				if (!document.body) return
				try {
					document.documentElement.doScroll("left")
					ready()
				} catch(e) {
					setTimeout(tryScroll, 0)
				}
			}
			tryScroll()
		}

		// (3.2)
		document.attachEvent("onreadystatechange", function(){

			if ( document.readyState === "complete" ) {
				ready()
			}
		})
	}

	// (4)
    if (window.addEventListener)
        window.addEventListener('load', ready, false)
    else if (window.attachEvent)
        window.attachEvent('onload', ready)
    /*  else  // (4.1)
        window.onload=ready
	*/
}

Разберем его по шагам.

  1. Код будет пытаться поймать событие onDOMContentLoaded различными способами. Вполне может получиться так, что несколько способов сработают независимо.

    Поэтому завернем обработчик handler в функцию ready(), единственный смысл которой - гарантировать, что handler будет вызван не более одного раза.

  2. Событие onDOMContentLoaded поддерживают достаточно новые Firefox, Opera, Safari/Chrome. Нет гарантии, что версия посетителя поддерживает это событие, но попробовать стоит.
  3. Браузер Internet Explorer не поддерживает onDOMContentLoaded, поэтому для него используются обходные пути.
    1. Функция tryScroll() пытается скроллить документ вызовом doScroll. Если получается - значит, документ загрузился, если нет - заказывает повторную попытку через setTimeout, и так пока документ наконец не будет готов. На практике это очень надежный способ, но есть проблемы с фреймами, поэтому используется только для окон верхнего уровня.
      Дополнительный фильтр - проверка document.body
    2. Событие document.onreadystatechange с проверкой readyState="complete", как и onDOMContentLoaded/onload, срабатывает после загрузки документа. Но, к сожалению, оно происходит уже после загрузки картинок. Поэтому onreadystatechange - вообще говоря, не то, что нам надо. Но это событие работает для фреймов, и при этом срабатывает до window.onload. Поэтому будем использовать и этот способ.
  4. Для тех браузеров, в которых не сработали предыдущие методы (например, очень старый Firefox), добавим вызов обработчика при событии window.onload.
    1. Для совсем древних браузеров, в которых нет addEventListener/attachEvent, вы можете раскомментировать и строчку (4.1). При этом, разумеется, возможен конфликт с другими обработчиками onload.

Этот код взят, с небольшими упрощениями, из библиотеки jQuery, а методы придуманы различными авторами.

Код из примера выше позволяет навешивать только один обработчик. Для поддержки нескольких - добавим дополнительную обертку:

readyList = []

function onReady(handler) {

	if (!readyList.length) {
		bindReady(function() {
			for(var i=0; i<readyList.length; i++) {
				readyList[i]()
			}
		})
	}

	readyList.push(handler)
}

Функция onReady при первом вызове вешает обработчик bindReady, который запускает все функции из списка readyList, а в дальнейшем просто добавляет новый обработчик в этот список.

Следующий пример демонстрирует использование onReady:

<html>
<head>
<script src="bindReady.js"></script>
<script src="onReady.js"></script>

<script>
  onReady(function() {
    var divs = document.body.getElementsByTagName('div')
    alert(divs[divs.length-1].innerHTML)
  })
</script>

<link rel="stylesheet" href="my.css" type="text/css">
</head>
<body>

<img src="img5.php"/>

<div>done</div>
</body>
</html>

Открыть в новом окне

Обработчик onReady выводит содержимое последнего тэга <div>, так что мы видим, что документ действительно загружен и разобран.

Картинка <img src="img5.php"/> загружается скриптом, который ждет 5 секунд. Это сделано для демонстрации, что onDOMContentLoaded вызывается до полной загрузки.

В новых Firefox, Safari/Chrome и во всех Internet Explorer поддерживается атрибут defer тэга <script>. Он позволяет загружать скрипт не блокируя загрузку страницы, а параллельно с ней.

Такая отложенная загрузка скриптов позволяет странице грузиться и отображаться быстрее. Обычно откладывают загрузку для толстых библиотек.

Скрипт является объектом, необходимым для загрузки страницы, и событие onDOMContentLoaded всегда срабатывает после загрузки скриптов.

Но Internet Explorer заканчивает рендеринг документа и делает скроллинг возможным до загрузки скриптов с атрибутом defer.
Поэтому doScroll сработает до загрузки таких скриптов.

Поэтому в браузере Internet Explorer описанный код (а значит и код jQuery) при наличии <script defer> будет работать некорректно, а именно - выполняться до загрузки таких скриптов.

Это может быть важно, если вы хотите использовать такие скрипты в коде инициализации.

В качестве альтернативы событию onDOMContentLoaded и функции bindReady можно рассмотреть скриптовую вставку в самом конце <body>:

<body>
...
<script>handler()</script>
</body>

Основной плюс такого подхода - работает везде, не нужен дополнительный кросс-браузерный код поддержки события.

Основной минус - меньшее удобство, нужен дополнительный код в HTML. Кроме того, тег <body> не закрыт, поэтому body.appendChild может не работать.

Исходные коды вы можете скачать в архиве.


Автор: PeaceCoder, дата: 11 января, 2010 - 20:13
#permalink

Вопрос на счет фреймов. Какое из событий в них происходит? DOMContentLoaded или window.onload ? Я когда махался с фреймами то у меня почемуто DomContentLoaded фрейма не выдавал событие и onload тоже не во всех браузерах.


Автор: Илья Кантор, дата: 11 января, 2010 - 20:17
#permalink

Какой браузер? Вы событие ловите внутри фрейма или снаружи?


Автор: PeaceCoder, дата: 12 января, 2010 - 00:05
#permalink

Событие ловил с наружи. А вот в каждом браузере по разному. в частности в FF3.5 DOMContentLoaded для фреймма не выдавал событие.


Автор: Илья Кантор, дата: 12 января, 2010 - 00:11
#permalink

Снаружи это событие не ловится...


Автор: Kolyaj, дата: 12 января, 2010 - 12:17
#permalink

>> * меньшее удобство, нужен дополнительный код в HTML
Чем удобство добавления скрипта в начало страницы отличается от удобства добавления скрипта в конец страницы? И какой нужен дополнительный код в HTML?


Автор: Илья Кантор, дата: 12 января, 2010 - 12:34
#permalink

В конце HTML нужен тэг script с вызовом ready.
При использовании функции bindReady - такой скриптовой вставки не нужно.


Автор: Kolyaj, дата: 12 января, 2010 - 13:05
#permalink

Если подключать все скрипты в конце страницы, то вообще никаких ready не надо, и код сильно упрощается.


Автор: Kiranatus (не зарегистрирован), дата: 1 сентября, 2010 - 17:32
#permalink

Точно! Или, добавить проверку переменной gbLoaded в функции, которым нужна полная загрузка документа, а в конце HTML просто добавить:
...
gLoaded = true;

Таким образом не придётся ждать загрузки картинок.


Автор: CTAPbIu_MABP (не зарегистрирован), дата: 17 января, 2010 - 01:59
#permalink
setTimeout(tryScroll, 0)

у оперы 9 были проблемы если поставлен таймаут 0, ставьте хотя бы 10


Автор: Hank (не зарегистрирован), дата: 16 июня, 2020 - 21:56
#permalink

yes, this sounds right! lubbock fence companies


Автор: Гость (не зарегистрирован), дата: 16 июня, 2020 - 22:35
#permalink

thanks, this is great! excavating near me


Автор: Misha_White, дата: 25 февраля, 2010 - 07:51
#permalink

В восьмом эксплорере не сработал пример...


Автор: Гость (не зарегистрирован), дата: 9 февраля, 2011 - 14:32
#permalink

Тоже самое. В IE8 сообщение появляется после загрузки страницы.


Автор: Shahurik, дата: 15 апреля, 2010 - 00:52
#permalink

В конце кода (отметка 4.1) можно предотвратить конфликт с поставленным обработчиком window.onload:

else
{
    var fn = window.onload || function(){};
    window.onload = function()
    {
        fn();
        ready();
    }
}

Автор: e.kubyshin, дата: 18 августа, 2010 - 14:20
#permalink

вот нагуглил DOM ready


Автор: Mikle, дата: 24 сентября, 2010 - 18:28
#permalink

Между 14 и 15 строчкой в "Код кроссбраузерной поддержки"
нужно добавить:
window.addEventListener( "load", ready(), false );
--
без этого не работает в "хроме" и "сафари"


Автор: Илья Кантор, дата: 6 декабря, 2010 - 23:35
#permalink

Можно подробнее? Что не работает?


Автор: brutaler (не зарегистрирован), дата: 4 августа, 2011 - 23:46
#permalink

Без этого не срабатывает handler в последних хроме и ff.


Автор: Гость_1 (не зарегистрирован), дата: 24 ноября, 2010 - 00:45
#permalink

>> Браузер гарантирует последовательное выполнение скриптов,
>> поэтому к моменту выполнения этой вставки все скрипты будут загружены.

Вроде бы не рабодает все равно с defer. Пример: в хеад - jquery с defer, в конце подключаю файл с кодом, который использует jquery. Если бы скрипты выполнялись последовательно, тогда не выскакивало бы '$ is not defined'. Правильно? Или когда яваскрипт подключен, а не встроен в страницу браузер уже не гарантирует последовательную работу? Что-то запутался


Автор: Гость_1 (не зарегистрирован), дата: 28 ноября, 2010 - 21:43
#permalink

Очень хотелось бы услышать комментарии к этому вопросу. Спасибо.


Автор: Илья Кантор, дата: 2 декабря, 2010 - 22:50
#permalink

Скрипт с DEFER может сработать как до так и после onDOMContentLoaded.


Автор: Гость_1 (не зарегистрирован), дата: 3 декабря, 2010 - 19:39
#permalink

Это не проясняет что вы имели в виду под "Корректно работает со скриптами с defer. Браузер гарантирует последовательное выполнение скриптов, поэтому к моменту выполнения этой вставки все скрипты будут загружены.". Или я в чем-то запутался. Пожалуйста "разжуйте" есть есть время. Спасибо.


Автор: Илья Кантор, дата: 6 декабря, 2010 - 22:27
#permalink

Немного исправил статью. По взаимодействию с DEFER:

DOMContentLoaded может быть как до так и после скриптов с Defer. Обычно после, в Firefox может быть до, если скрипт в кеше.


Автор: Гость (не зарегистрирован), дата: 8 июля, 2011 - 22:55
#permalink

почитав комментарии, понял что этот код, мало того что громоздкий, имеет кучу нюансов, так он ещё и ни фига не гарантирует Sad
скорее в 99% и 999тысчяных процентов, он нафиг ни кому ненужен.
А автору принцип KISS. В коде и без этого забот хватает, а насчёт кросс браузерности, даже в самом худшем варианте,
if(ослик)alert("осликов на сайт не пускаем");
Почему миллионы разработчиков должны что то изобретать, когда ИЕ жопу морщит(извините но других слов ненашол). Объявить байкот ИЕ, хотя бы на личных сайтах, и они сами очень быстро все проблемы связанные с кроссбраузерностью, раз и на всегда устранят, иначе ИЕ безнадёжно устареет.


Автор: tenshi, дата: 17 июля, 2011 - 10:48
#permalink

что мешает просто проверять /^(interactive|complete)$/.test( document.readyState ) и не париться? работает во всех современных браузерах.

.ня


Автор: popov654, дата: 9 сентября, 2011 - 01:02
#permalink

Хорошо, когда работает во всех, а не только в современных. Хотя бы начиная с Firefox1.5/2.0, IE6, Netscape8/9, Opera9 и Safari3


Автор: lex-tomsk2@yandex.ru (не зарегистрирован), дата: 2 января, 2012 - 18:59
#permalink

Немного подумав об "Альтернатива событию onDOMContentLoaded", выношу на СУД свое решение:
создаем ready.js с кодом:

var ready={
	handlers : [],
	add : function(name,handler){
		if(document.body) {
			handler();
			return;
			}
		this.handlers[name]=handler;
	},
	work : function(){
		if(!document.body) {setTimeout("ready.work()",200);return;}
		for(var name in this.handlers){
			this.handlers[name]();
		}
	}
}
ready.work()

Подключаем его в начале страницы, внутри страницы используем регистрацию:

ready.add('name',function(){
	alert("Документ : "+ ((document.body) ? ("yes") : ("no")))
	});

В комментариях код не нуждается Dance3 .


Автор: Гость (не зарегистрирован), дата: 24 января, 2012 - 06:11
#permalink

Не лучшее решение.
Сразу бросаются в глаза "тяжелые зависимости", вроде setTimeout('ready.work();'...);. Плюс исполнение кода в неявном eval'е и итерация по элементам массива циклом for-in.
Плюс, если предполагется множество обработчиков, то логичнее вызывать их в порядке добавления, чего не гарантирует выбранный Вами тип цикла.
Да и проверка document.body не гарантирует ожидаемого.

Для большей уверенности, в том, что это сработает там, где кто-либо преопределил прототип Array или ожидает срабатывания обработчиков в порядке их назначения используйте

function Ready() {
	var handlers = [];
	
	(function waitBody()
	{
		if (document.body)
			for (var i = 0, l = handlers.length; i < l; ++i)
				handlers[i]();
		else
			setTimeout(function() {
				waitBody();
			}, 200);
	})();
	
	return {
		addHandler : function (handler) {
			if (document.body)
				handler();
			else
				handlers.push(handler);
		}
	};
}

А использовать:

var customObject = new Ready();
customObject.addHandler(function(){
    alert("Документ : "+ ((document.body) ? ("yes") : ("no")))
    });

Автор: lex-tomsk2@yandex.ru (не зарегистрирован), дата: 5 февраля, 2012 - 19:41
#permalink

Согласен, что немного поспешил с ready.js.
Да и если честно - не знал, что в setTimeout можно передавать функцию... Blink

Переделал с учетом критики:

Ready={
	pr:"onDocumentReady_", // защита от изменений прототипа массива
	handlers:[],
	add:function(name,handler){
		if(document.body && !this.handlers[this.pr+name]){
			handler();
		}
		this.handlers[this.pr+name]=handler;
	},
	work:function(){                /* интересное место */
		if(!document.body) {setTimeout(this.work,200);return;}
		for(name in this.handlers){
			if(name.indexOf(this.pr)==0) this.handlers[name]();
		}
	}
};
Ready.work();

Параметр name передавать необходимо, чтобы исключить повторное выполнение.
В замыканиях я не силен, поэтому если можно их избежать без вреда для кода, то избегаю.
Интересное место - сначала думал, что передаваемая функция будет работать в глобальном контексте (по аналогии со строкой), и нужно будет ставить Ready.work, но все оказалось намного приятнее.
Толком не протестировал. Но вроде должно работать.

Вопрос к предыдущему Гостю: что Вы имеете в виду, когда говорите, что document.body не гарантирует ожидаемого? Я думаю, что если body доступен, то уже можно работать с его содержимым.


Автор: Раед, дата: 19 марта, 2012 - 15:02
#permalink

если body доступен, то уже можно работать с его содержимым.

Не факт, document.body может быть доступен до загрузки всего содержимого


Автор: Раед, дата: 7 мая, 2012 - 10:51
#permalink

Есть ещё 1 простой вариант без поддержки фреймов. Можно проверять document.documentElement.innerHTML на наличие закрывающего тега body. Странно, что до этого раньше никто не додумался, или я чего-то не понимаю?


Автор: DarkDaemon, дата: 30 мая, 2013 - 03:14
#permalink

Пробовал так, но работает это не всегда:

docreadytimer = setInterval("if (document.getElementsByTagName('html')[0].innerHTML.indexOf('/body') > 0){clearInterval(docreadytimer); start();}", 50);

Видимо, современные браузеры достраивают документ и выводят его пользователю в ходе загрузки и еще до загрузки всего содержимого, т.е. в структуру документа проставляют < /body >< /html >


Автор: Joker99 (не зарегистрирован), дата: 26 апреля, 2014 - 20:27
#permalink

Какбэ да, потому что при парсинге открывающегося тэга браузер автоматом подставляет закрывающий


Автор: Гость (не зарегистрирован), дата: 24 августа, 2012 - 09:29
#permalink

Спасибо за код. Почти везде работает.


Автор: Гость (не зарегистрирован), дата: 29 августа, 2014 - 18:16
#permalink

Не могу понять логику кода. Помогите пожалуйста. Возможно я что-то недопонимаю. Попытался разобрать исходный код автора пошагово:

пункт_1. в OnReady в качестве аргумента "Хэндлера-1" передаётся функция, которая выводит алёртом значение последнего Дива.

пункт_2. внутри функции OnReady:
пункт_2-а) благодаря тому, что readyList[] пустой = вызывается функция bindReady, которой в качестве аргумента "Хэндлера-2" передаётся функция, которая вызывает все функции из списка readyList[], который пока ещё ПУСТ(!).
пункт_2-б) ПОСЛЕ вызова функции bindReady, переданный в неё из функции OnReady "Хэндлер-1" отправляется в массив readyList[].

пункт_3. внутри функции bindReady:
доходим по логике до 18-й строки кода, где, предположим, мы получим TRUE и выполнится функция tryScroll().

пункт_4. внутри функции tryScroll():
тут called=False, идём дальше, и предполагаем, что document.body=TRUE => тогда запускается блок TRY, в котором вызывается функция ready().

пункт_5. внутри функции ready():
called становится true, и запускается handler(), т.е. функция которая была передана в функцию bindReady через аргумент handler, т.е. выше упомянутый "Хэндлер-2", который запускает все функции из списка readyList[], который к данному моменту ПУСТ (!) из-за того, что из пункта "2-а" мы улетели в пункт "3" (и пункт "2-б" ещё не выполнялся). ТО ЕСТЬ, по идее НЕЧЕМУ выполняться.

пункт_6.
- из функции ready() возвращаемся в блок TRY;
- крутим tryScroll пока документ не будет ГОТОВ;
- выходим из конструкции if () на 30 строке кода;
- на 33-й строке ready() вешается как обработчик (при этом в теле этой функции на данный момент до сих пор содержится handler() который есть "Хэндлер-2", то есть выполнение ПУСТОГО списка readyList);
- и улетаем из функции bindReady обратно в функцию OnReady, из которой её вызывали, и попадаем на пункт "2-б" в котором добавляется "Хэндлер-1" в список функций вызываемых "Хэндлером-2" (который уже нигде по коду не вызывается);
- выходим из функции OnReady.

ВОПРОС: Откуда же тогда, и на каком этапе кода, будет вызван обработчик "Хэндлер-1", который собственно и отвечает за показ Названия Последнего тэга Дива с помощью алёрта ???


Автор: Гость (не зарегистрирован), дата: 3 сентября, 2014 - 16:32
#permalink

Не правильнее в строке 42 вместо:

if (window.addEventListener)

сделать

esle if (window.addEventListener)


Автор: dufus (не зарегистрирован), дата: 13 октября, 2014 - 12:57
#permalink

Добрый день. А почему функция onReady не срабатывает если ее запихнуть в условие ?.....к примеру

if (/(home)/i.test(url)|| window.location.pathname.charAt(1) === '') {
 onReady(function() {
		document.getElementById("tab-menuSrc").style.display="block";
		document.getElementById("menuSrc").className="menuSrcOnMouseOver";
		document.getElementById("tab-menuServices").style.display="none";
  })
}

Автор: Разработчик (не зарегистрирован), дата: 12 июня, 2018 - 21:22
#permalink

Очень понравился материал, но можно и подробнее


Автор: Devlin Martin (не зарегистрирован), дата: 5 августа, 2020 - 12:12
#permalink

О, благодаря этому обмену вы раскрыли многие мои идеи, поэтому я могу узнать больше о многих ценных вещах. run 3


Автор: Гость (не зарегистрирован), дата: 12 апреля, 2022 - 21:36
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 01:25
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 14:29
#permalink

Автор: brownlaur57 (не зарегистрирован), дата: 1 июля, 2022 - 12:12
#permalink

Hi there, I am here to find new friends who love playing online games. We can make friends and play tunnel rush in our free time. It's so funny, let's try it!


Автор: danielusa, дата: 30 июля, 2022 - 07:19
#permalink

wow, I went crazy reading your post, it's very good and informative. and if you have free time then I invite you to play the game wordle and io games with me.


Автор: Гость (не зарегистрирован), дата: 6 октября, 2022 - 06:49
#permalink

Hope someone can explain more detail. I have the same problem five nights at freddy's.


Автор: keo nha cai (не зарегистрирован), дата: 6 октября, 2022 - 07:08
#permalink

I was looking for another article by chance and found your article keo nha cai I am writing on this topic, so I think it will help a lot. I leave my blog address below. Please visit once.


Автор: Гость (не зарегистрирован), дата: 10 октября, 2022 - 12:28
#permalink

cuphead I can make out a great deal of essential information.


Автор: kemmer (не зарегистрирован), дата: 11 октября, 2022 - 10:30
#permalink

Вы вызываете мое неугасающее восхищение за то, что написали такое замечательное произведение. Мне очень понравилось читать эту статью, и я думаю, что она может быть лучшей из тех, что я читал до сих пор. В идеале вы должны поддерживать один и тот же высокий стандарт на протяжении всего выполнения этого задания. fnf mod


Автор: tomusa, дата: 14 ноября, 2022 - 11:56
#permalink

The information you share is very good and exciting, I will definitely follow your next posts. krunker


Автор: Zac Macintyre (не зарегистрирован), дата: 5 января, 2023 - 15:20
#permalink

Photo gallery is filled and approved for the use of the offers. The discount of the Diesel Gas Station Near Me are ensured for the challenges. Mandatory look is fit for the mixing of the goals for the native and all joys for the main field for the citizens.


Автор: kevintexas0106 (не зарегистрирован), дата: 9 марта, 2023 - 04:45
#permalink

I am very impressed with the information drift boss you share, which will play an important role in adding material to the topic the impossible quiz people are researching.


Автор: Гость (не зарегистрирован), дата: 13 марта, 2023 - 07:09
#permalink

This is an article full of interesting and useful information. You can share it on many subway surfers websites so that everyone can learn and learn together.


Автор: Гость (не зарегистрирован), дата: 29 марта, 2023 - 11:40
#permalink

I appreciate your efforts over the past time, you have shown everyone that this article of yours wordle deserves everyone's recognition. Great article!


Автор: lunadam (не зарегистрирован), дата: 20 апреля, 2023 - 07:50
#permalink

Before images and other backrooms game items that do not alter the structure of the document have finished loading, this event is fired as soon as the DOM document is ready. Because images can take a while to load, this is particularly practical because the onDOMContentLoaded handler can alter the page and instantiate interfaces right backrooms immediately without having to wait for everything to load.


Автор: revelationresist (не зарегистрирован), дата: 21 апреля, 2023 - 12:59
#permalink

No ready is required and the code is substantially streamlined if all the scripts are connected at the end of the page. flappy bird


Автор: Гость (не зарегистрирован), дата: 19 мая, 2023 - 10:09
#permalink

I've heardle realized the importance of taking care of my physical health to maintain energy levels throughout the day


Автор: Гость (не зарегистрирован), дата: 20 мая, 2023 - 06:43
#permalink

If all the scripts are linked to the bottom of the page, no ready is needed, and the code is greatly streamlined.


Автор: Dilan Turner (не зарегистрирован), дата: 24 мая, 2023 - 09:13
#permalink

Автор: Andrea Newsom (не зарегистрирован), дата: 24 мая, 2023 - 09:25
#permalink

Автор: Keiren Harrison (не зарегистрирован), дата: 24 мая, 2023 - 09:44
#permalink

Awesome post, thank you for sharing this one. https://asbestosremovalbrooklyn.com/asbestos-removal-brooklyn-ny/


Автор: Гость (не зарегистрирован), дата: 5 июня, 2023 - 05:00
#permalink

You've come this far and I think that's great, keep chasing your dreams and one day you'll reach the top and then you'll see how great you've become . pge outage map


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
1 + 9 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum