Неожиданный бесконечный цикл JavaScript при проверке тега тела

Я собирался использовать сценарий ASAP, который проверяет, загружен ли тег body, но он приводит к зависанию всей страницы.

Вот:

while (!document.body)
    if (document.body) console.log('loaded');

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


person Jinx    schedule 07.06.2014    source источник
comment
Я озадачен, почему это превращается в бесконечный цикл и замораживает страницу. - потому что это бесконечный цикл? Парсер DOM останавливается, пока JS выполняется синхронно.   -  person Fabrício Matté    schedule 07.06.2014
comment
callmenick.com/2014/06/04/check-everything -loaded-javascript   -  person mplungjan    schedule 07.06.2014
comment
Вам нужно использовать события. Вы не можете сделать это с помощью петли.   -  person meagar    schedule 07.06.2014
comment
Если вам нужна простая функция javascript, которая сообщит вам, когда DOM готова, см. Здесь: чистый JavaScript, эквивалентный $ .ready () jQuery, как вызвать функцию, когда страница / дом готова для этого   -  person jfriend00    schedule 07.06.2014


Ответы (2)


Javascript однопоточный. Пока этот цикл выполняется, больше ничего не выполняется, поэтому тело не может быть загружено. В теле цикла нет ничего, что изменяло бы значение document.body, поэтому, если оно не установлено при запуске, его никогда не будет.

person Barmar    schedule 07.06.2014
comment
Я не думаю, что эта проблема связана с однопоточностью JS, скорее с однопоточностью пользовательского интерфейса браузера. - person Fabrício Matté; 07.06.2014
comment
Так что это зависит от того, где включен сценарий. Если он запускается до тега body, он завершится ошибкой, после этого все должно быть в порядке. - person martin.code; 07.06.2014
comment
Считаю их одним и тем же. Все на странице эффективно выполняется в одном потоке. - person Barmar; 07.06.2014
comment
@ feat.martin Правильно - это либо цикл с нулевым запуском, либо бесконечный цикл, но ничего между ними. - person Barmar; 07.06.2014
comment
Но потом мне это не нужно: D @ feat.martin - person Jinx; 07.06.2014
comment
@ feat.martin Использование после полностью излишне. Тело цикла while никогда не будет введено. - person meagar; 07.06.2014
comment
Блин, я думал, что я такой умный. - person Jinx; 07.06.2014
comment
@Barmar Ну, однопоточность JS - это аспект языка ECMAScript. Тот факт, что он останавливает парсер DOM, больше связан с остановкой потока пользовательского интерфейса браузера во время выполнения JS-кода. - person Fabrício Matté; 07.06.2014
comment
Почему бы не использовать document.onload? - person martin.code; 07.06.2014
comment
@ feat.martin, он явно пытается что-то сделать ДО загрузки документа, может быть, какой-то прогресс - person Barmar; 07.06.2014
comment
Но почему бы тогда просто не запустить операцию в скрипте, включенном в голову? Обнаруженный Javascript просто начнет выполняться браузером, даже если страница не полностью загружена, а затем он может просто остановить эту операцию при возникновении события onload? - person martin.code; 07.06.2014
comment
И да, утверждение, что он выполняется в одном потоке, может быть приемлемым упрощением, но то, как вы это сформулировали, похоже, что парсер DOM работает внутри потока JS. Но очевидно, что это два совершенно разных зверя, которых браузер абстрагирует от кажущейся синхронности одного потока. - person Fabrício Matté; 07.06.2014
comment
Другими словами, интерпретатор JS и его характеристики (однопоточные) не имеют абсолютно ничего общего с модулем визуализации DOM, это поток пользовательского интерфейса, который отвечает за синхронный запуск модуля визуализации DOM и интерпретатора JS. - person Fabrício Matté; 07.06.2014
comment
Они могут быть технически отдельными, но с точки зрения программиста Javascript вся загрузка, рендеринг и выполнение скриптов по сети эффективно выполняется в одном синхронном потоке. Во время выполнения сценария ничто не может изменить DOM, кроме сценария. Если это упрощение, пусть будет так - если вы на самом деле не разработчик браузера, это полезное упрощение. - person Barmar; 07.06.2014

Этот код выполняется синхронно, поэтому, если сначала document.body не определен, он не позволяет браузеру заполнять его между итерациями. Для этого используйте setTimeout или setImmediate или, еще лучше, прослушайте DOMContentLoaded или используйте $(document).ready() jQuery.

(function ready() {
  if (document.body) console.log('loaded');
  else setTimeout(ready, 500); // delay 1/2 second
})();
person Klaus    schedule 07.06.2014
comment
Да, это было мое второе решение - person Jinx; 07.06.2014
comment
Как я прокомментировал ранее, учитывая это: stackoverflow.com/questions/2920129/. Почему бы просто не открыть сначала тег скрипта в голове, который просто начинает делать все, что вы хотите, до загрузки тела, а затем фальсифицировать условие для этого до того, как тело загрузится? Однако мне сложно понять вашу мотивацию, обычно, как говорит @Klaus, нужно слушать, когда DOM доступна. - person martin.code; 07.06.2014
comment
@ feat.martin Вот что пробовал в вопросе. Он запустил цикл while и ожидал, что условие не сработает, когда тело будет загружено. Проблема в том, что тело не может загружаться во время работы скрипта. Вот почему это setTimeout необходимо - оно позволяет сценарию периодически выходить и перезапускаться, чтобы тело загрузилось. - person Barmar; 07.06.2014