Фитискин Александр

Не гони коней!

При разработке последнего проекта я взял на себя задачу организовать подгрузку контента на страницу с помощью Ajax. XMLHTTP-соединение успешно устанавливалось, я получал необходимый контент и с помощью innerHTML вставлял его в скрытый блок на странице, чтобы уже оттуда выдергивать необходимые части. И тут я наткнулся на грабли: в ответ на мои запросы getElementById или getElementsByTagName браузер выдавал undefined вместо необходимых мне подгруженных элементов.

Как оказалось, грабли таились в том, что я слишком торопился: с момента вставки полученного контента на страницу и до момента обращения к его элементам браузер не успевал добавлять новые элементы в DOM-дерево страницы. Решение: задать таймаут, тем самым дать браузеру время для построения дерева DOM. А если мы поместим в конец загружаемого контента узел-метку (например, пустой div с id=flag), то сможем определить закончил браузер свою работу, или нам нужно еще немного подождать.


var hiddenDiv; // скрытый контейнер на странице
var oXmlHttp = createXmlHttp();
oXmlHttp.open("get", url, true);
oXmlHttp.onreadystatechange = function ()
{
 if (oXmlHttp.readyState == 4)
 {
 if (oXmlHttp.status == 200)
 {
 hiddenDiv.innerHTML = oXmlHttp.responseText;
 var t = setTimeout("handle()", 100);
 }
 }
}
oXmlHttp.send(null);
function handle()
{
 if (document.getElementById('flag') != undefined)
 {
 // Дерево DOM готово, можем разбирать полученный контент по частям
 }
 else
 {
 var t = setTimeout("handle()", 100);
 }
}

В зависимости от размера получаемого контента следует установить нужный таймаут.

Алексей
12 сентября
Кросс-пост с ХабраХабра?
Guest
12 сентября
Наверное проще было бы писать:
hiddenDiv.innerHTML = oXmlHttp.responseText+'<div id="flag"></div>';
чем добавлять этот див в каждый контент, или:
hiddenDiv.innerHTML = oXmlHttp.responseText+
'<script type="text/javascript">'+
'<!--'+
'handle()'+
'//-->'+
'</script>';
?



Говорящая кружка
19 сентября
Александр, советую убивать таймер после выполнения.
Фитискин Александр
26 сентября
Алексей, это оригинал статьи, который я продублировал на ХабраХабр
Фитискин Александр
29 сентября
Guest, добавление скрипта не считаю верным, а вот решение с добавлением div'а уже непосредственно в скрипте идея хорошая!
Фитискин Александр
29 сентября
Говорящая кружка, да конечно
masic
28 октября
Проблему с задержкой построения DOM лично я решаю куда проще ... тег script размещается в конце html, перед </body> ... заодно позволяет решить проблему с остановкой рендеринга страницы при подгрузке внешних js
Фитискин Александр
28 октября
masic, наверное вы не совсем поняли суть проблемы. Я говорю о построении дерева DOM для контента загруженного на страницу с помощью Ajax
Wowa Savin
28 ноября
Вместо setTimeout("handle()", 100);
Достаточно setTimeout("handle()", 10);
Что бы исключить мерцания, если после вставки должны произойти какие-либо изменения. Меньше 10 не имеет смысла ставить, т.к. таймер работает с дискретность 18 миллисекунд. Но и при очень маленьких значениях может не произойти переключения на тред идексации имён, а сразу выполнять скрипт по таймауту.