Удивительная история document.write

в 15:54, , рубрики: 42, document.write, javascript, бесполезный код, браузеры, ненормальное программирование, Программирование, Разработка веб-сайтов, рекурсия, метки:

Метод document.write — один из самых странных методов. Он вставляет HTML-код на страницу сразу после себя. Точнее говоря, сразу после тега <script>, внутри которого он расположен. И только в том случае, если документ еще не был загружен полностью. А если был? Тогда страница очищается и заменяется на, что было указано.

Можно вставить строку, которая явно сломает остальную страницу:

document.write('<plaintext>')

Или можно поиграть в русскую рулетку:

if (Math.random() > 0.9)
  document.write('<!--')


Оказывается, тот факт, что текст вставляется сразу после тега <script> — это важно. Например:

<script>
  document.write('<script src="jquery.js"></' + 'script>');
  alert(jQuery.guid)
</script>

Данный код выведет ошибку о том, что переменная jQuery не объявлена.
С другой стороны:

<script>
  document.write('<script src="jquery.js"></' + 'script>');
</script>
<script>
  alert(jQuery.guid)
</script>

А этот код выполнится без ошибок, потому что второй тег <script> не начнет исполняться до тех пор, пока не будет полностью обработан скрипт, подгруженный из первого тега.

Дальше становится все любопытнее. Представим, что есть такой код:

<script>
  console.log('a');
  document.write('<script src="printC.js"></' + 'script>');
  console.log('b');
</script>
<script>
  console.log('d');
</script>

А в файле printC.js содержится следующее:

console.log('c')

Данный код выведет в консоль следующее:

a
b
c
d

Из этого примера видно, что весь код из первого тега <script> после document.write был выполнен сразу же, а вот второй тег начал исполняться только после того, как завершил свою работу printC.js.

Следует помнить. что этот способ вставки контента работает только непосредственно во время загрузки документа. Что будет, если вызвать document.write после того, как он уже загружен? Было бы логично выдать ошибку, или не делать ничего. Вместо этого вся существующая страница стирается, а на ее место выводится переданная строка:

setTimeout(function(){
  document.write("Oops");
})

Существует ли нормальный повод применять document.write?

Я о таком не слышал. По всей видимости, он используется в баннерокрутилках, потому что позволяет показать отслеживающую картинку вместо AJAX-запроса, если пользователь заходит на сайт через Netscape 2. В современном же мире он особо ни для чего не нужен.

Правда, иногда встречаются замечательные инструменты, которые незаметно оборачивают передаваемый вами HTML в вызовы document.write.

Можно ли вызвать document.write внутри document.write?

Ага!

Типа, бесконечно много раз?

Нет, 20 раз.

Серьезно? Двадцать?

Ага.

Google Chrome, несомненно, более совершенный браузер — там можно аж 21 раз.

Они что, независимо друг от друга до этого додумались?

Разработчики Firefox первыми исправили баг, потенциально позволявший уронить браузер, а разработчики Webkit скопировали их решение. Ходят слухи, что в IE тоже есть некий предел, но он еще ниже.

Можно ли сломать браузер еще быстрее?

<div id="uniqid">
  <script language="JavaScript" type="text/JavaScript">
    document.write(">"+document.getElementById('uniqid').innerHTML+"<");
  </script>
</div>

(Код взят из тикета)

Какие еще глупости можно натворить с document.write?

Да какие угодно!

Например, можно сделать синхронный AJAX-запрос и вставить его результат непосредственно в тело страницы:

x = new XMLHttpRequest()
x.open('GET', "", false)
x.send()
document.write(x.responseText);

Отправка запроса заблокирует загрузку основной страницы, и содержимое ответа будет вставлено так, как если бы оно изначально располагалось на загружаемой странице. В данном случае вместо URL передана пустая строка, поэтому загружаться будет та же самая страница, а она, в свою очередь, снова начнет загружать сама себя, и так до бесконечности*.

* Под «до бесконечности» подразумевается 20 раз. Или 21. Или еще меньше, если вы в IE.

В общем, можно развлекаться по-разному.

Что-нибудь еще?

В текущей спецификации этого нет (хотя было в прошлых версиях), но можно передавать в document.write несколько параметров, например:

document.write("П", "Р", "Е", "В", "Е", "Д");

Если метод бесполезен, зачем я про него вообще читаю?

А вот это действительно хороший вопрос!

Примечание переводчика:

Любопытно, что если что только первый вызов document.write после загрузки страницы очищает ее содержимое. Последующие вызовы дописывают текст после первого.

Автор: impwx

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js