document.write игнорируется перед DOMContentLoaded при ожидании загрузки скрипта с высокой задержкой

Я пробовал много разных способов сформулировать этот вопрос на Google и др. Без удачи. Даже не уверен, что название этого вопроса отражает нюанс проблемы. Я постараюсь объяснить, а затем показать эксперимент. Я надеюсь, что кто-то (ы) сможет указать на некоторые объяснения того, что происходит.

Дано:

  • до конца BODY у вас есть скрипт (A), который программно вставляет элемент скрипта (используя мой предпочтительный метод document.createElement) в документ, который ссылается на remote-script (B)
  • remote-script B выполняет document.write любого содержимого (например, "hello, world")
  • до конца BODY и сразу после сценария A у вас есть сценарий (C), который ссылается на удаленный сценарий, загрузка которого занимает некоторое время (например, 1 с)

Что произойдет, это то, что A выполнит, вставит B в документ и начнет загружать ресурс. Пока B загружает, C будет выполняться и ждать из-за задержки. Пока C ожидает, B загружается и выполняется; мы еще не нажали DOMContentLoaded; document.readyState все еще "загружается". Document.write из B игнорируется; сожрал, как будто мы пост-DOMContentLoaded. C завершает загрузку и выполняет.

Эксперимент:

Я использую Cuzillion, чтобы создать задержку. Если вы посмотрите на изображение водопада, вы также увидите сообщение console.log, которое показывает, что все выполняется до того, как DOM достигнет "интерактивного" readyState (то есть DOMContentLoaded).

Что я ожидаю в качестве вывода в браузере:

TOP
hello, world
hello again, world
BOTTOM

Что я получаю в качестве вывода:

TOP
hello, world
BOTTOM

В моем эксперименте вы заметите, что я добавил еще один сценарий между тем, что мы определяем как A и C. Назовите это A'я полагаю; это показывает, что если вы динамически добавляете скрипт, имеющий текст (т.е. не удаленный скрипт), который содержит document.write, doc.write в A'сработает.

Кроме того, dummy.js и CSS-файлы взяты из JSFiddle. Они не преступники; Я могу воссоздать эту проблему где угодно.

Вещи, которые я знаю:

  • если вы замените C на IMG, проблем не будет
  • если вы замените C на IFRAME, проблем не будет
  • если вы двигаете A после C, нет проблем

Сейчас:

Возможно, для этого есть вполне веская причина. Должно быть, так как все браузеры, в которых я тестировал, ведут себя примерно одинаково. Что я хотел бы знать, почему? Любые объяснения, подсказки и / или указатели приветствуются. Даже намеки, как "Это в спецификации, тупой:)" У меня толстая кожа; Я могу с этим справиться.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я ненавижу document.write. Я не намерен поддерживать или поддерживать его использование каким-либо образом. Однако, учитывая характер моей работы, я должен сейчас обойти ее, и эта странность возникла на мне. Таким образом, я хотел бы избегать комментариев вдоль линии "Вы не должны использовать document.write", потому что в это, я уже верю:)

2 ответа

Решение

Выполнение document.write из асинхронно загружаемых сценариев не поддерживается в HTML5 именно потому, что это очень сложно: у вас нет способа узнать, будет ли ваш сценарий выполняться до или после DOMContentLoaded. См. http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html и http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html, шаг 2 и http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html шаг 3. Дело в том, что наличие записи, если сценарий превосходит гонку до DOMContentLoaded, но игнорируется, если она проигрывает, будет довольно странным и приведет к тому, что страницы иногда работают, а иногда и не зависят от условий сети.

SEC7112: Сценарий из https://raw.github.com/gist/2141272/1a6bf0111ce10d55e628e3736a9d381d82e8a780/external-with-docwrite.js был заблокирован из-за несоответствия типов пантомимы

Это твоя проблема. Скрипт передается как text/plain, который не является допустимым MIME-типом для JavaScript.

Другие вопросы по тегам