2012-03-20 2 views
3

Я пробовал много разных способов рассказать об этом вопросе google et al., Не повезло. Даже не уверен, что название этого вопроса отражает нюанс проблемы. Попробую объяснить, тогда покажите эксперимент. Я надеюсь, что кто-то (-ы) сможет указать на какое-то объяснение того, что происходит.document.write проигнорирован перед DOMContentLoaded, ожидая загрузки сценария с высокой задержкой

Дано:

  • до конца тела, у вас есть скрипт (A), который программно вставляет элемент сценария (используя мой предпочтительный метод, document.createElement) в документ, который ссылается на пульт -script (B)
  • remote-script B выполняет document.write любого контента (например, «привет, мир»)
  • до конца 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 'WILL работает.

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

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

  • если заменить C с IMG, не проблема
  • если заменить C с IFRAME, нет никакой проблемы
  • при перемещении после C , нет никакой проблемы

Сейчас:

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

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

ответ

5

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

+0

Спасибо, @ boris-zbarksy. Великие указатели. Должно было начаться с этих спецификаций. Они помогут при перемещении через исходный код webkit. Я не закончил разбивать все условия, но в ответ на ваше утверждение о том, что должен сделать DOM, я спрашиваю: почему сценарий A выполняется нормально при перемещении после скрипта C? Это только когда дело до C, что это проблема. Опять же, я действительно не хочу, чтобы document.write работал, мне больше любопытно, что здесь происходит. – Gus

+0

Итак, когда C доходит до A, тогда B (который загружается A) на самом деле дожидается до завершения обработки. Это объясняет, что деструктивная запись игнорируется в этом случае. Но я полагаю, что мне просто нужно признать, что браузер выполнит A (когда дело доходит до C) знание разбора еще не закончено - [поскольку readyState еще не интерактивен] (http://www.whatwg.org/specs/web- apps/current-work/multipage/the-end.html # the-end), но все равно будет обрабатывать документ как закрытый. Немного странного состояния гонки, ИМО. – Gus

+0

@Gus Я бы не ожидал, что изменение порядка A и C в вашей установке повлияет на что угодно. Можете ли вы опубликовать ссылку на версию с отменой A и C? –

0

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

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

+0

Спасибо, Колинк. Однако это только функция вашего браузера. В Chrome это выполняется. Я пытался сохранить источник для всех, чтобы увидеть, но я переместил этот файл на один из моих серверов и обновил Fiddle. Можете попробовать еще раз. – Gus