Почему document.write считается «плохой практикой»?

364

Я знаю, document.writeэто считается плохой практикой; и я надеюсь составить список причин, чтобы представить стороннему поставщику информацию о том, почему они не должны использоваться document.writeв реализациях своего аналитического кода.

Пожалуйста, укажите причину, по которой вы считаете document.writeэто плохой практикой.

FlySwat
источник

Ответы:

243

Несколько из более серьезных проблем:

  • document.write (далее DW) не работает в XHTML

  • DW напрямую не модифицирует DOM, предотвращая дальнейшие манипуляции (пытаясь найти подтверждение этому, но в лучшем случае это ситуативно)

  • DW, выполненный после завершения загрузки страницы, перезапишет страницу или напишет новую страницу, или не будет работать

  • DW выполняется там, где встречается: он не может внедрить в заданной точке узла

  • DW эффективно пишет сериализованный текст, который концептуально не работает с DOM, и это простой способ создавать ошибки (.innerHTML имеет ту же проблему)

Намного лучше использовать безопасные и дружественные DOM методы манипулирования DOM

annakata
источник
39
-1, это абсолютно модифицирует DOM. Все остальное в порядке. Хотя я понимаю необходимость зависеть от структуры и методов, которые могут уберечь вас от вреда, это может быть случай выброса ребенка с водой из ванны.
cgp
7
FireBug не является истинным представлением DOM. Это попытка Mozilla разобрать HTML в DOM. Вы можете иметь полностью испорченный HTML в правильном представлении Firebug DOM.
FlySwat
8
DOM - это структура данных, используемая для отображения страницы, а также альфа и омега того, что пользователь видит на странице. Вы правы, что HTML! = DOM, но это несущественно для вопроса о том, является ли DOM модифицирован DW. Если DW не изменил DOM, вы не увидите экран - это верно для всех браузеров и всегда будет таким, пока DOM - это то, что используется для визуализации страницы.
cgp
8
«DW выполняется там, где встречается» - не всегда недостаток, действительно, это может считаться преимуществом для определенных вещей, например, добавления элементов скрипта (фактически, единственное, для чего я бы использовал DW, и даже тогда я бы подумал дважды) ,
nnnnnn
7
@RicardoRivaldo Да, они делают, если document.writeвызывается после того, как документ закончил загружаться
Izkata
124

На самом деле с этим все document.writeв порядке. Проблема в том, что злоупотреблять им действительно легко. Грубо, даже.

С точки зрения поставщиков, предоставляющих аналитический код (например, Google Analytics), для них это самый простой способ распространения таких фрагментов.

  1. Это держит сценарии маленькими
  2. Им не нужно беспокоиться о переопределении уже установленных событий загрузки или включении необходимой абстракции для безопасного добавления событий загрузки
  3. Это очень совместимо

До тех пор, пока вы не пытаетесь использовать его после загрузки документаdocument.write , по моему скромному мнению,это не присуще злу.

Питер Бейли
источник
3
document.write делает ужасные вещи с html-парсерами и только «чрезвычайно совместим» в простых случаях.
olliej
27
Как и вставка тега аналитики? Это, в конце концов, часть первоначального вопроса. И под чрезвычайно совместимым, я имею в виду просто необработанную поддержку браузера для метода document.write.
Питер Бейли
Все, что работает с последними версиями Chrome / IE / Safari / Opera / FireFox, считается совместимым.
Pacerier
2
Переопределение событий загрузки? А для чего addEventListener?
m93a
Chrome не будет запускать document.writeвызовы, которые вставляют скрипт, когда выполняются определенные условия.
Flimm
44

Другое законное использование document.writeпроисходит из примера HTML5 Boilerplate index.html .

<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.3.min.js"><\/script>')</script>

Я также видел ту же технику для использования json2.js JSON-анализа / stringify polyfill ( необходим для IE7 и ниже ).

<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>
Кевин Хакансон
источник
11
Неплохо здесь, но все же «лучше» использовать функции манипулирования DOM - даже Google делает это для Google Analytics. Фрагмент здесь .
BMiner
8
@BMiner, если вы вставляете scriptэлемент с помощью DOM-манипуляции, он загружается синхронно? Если это не так, это не замена.
Джон Дворак
2
@JanDvorak - Хороший вопрос; при использовании манипуляций с DOM браузеры обычно загружают скрипт асинхронно. Вы можете использовать onloadсобытие DOM, чтобы определить, когда асинхронно загруженный скрипт доступен для использования.
BMiner
1
@JanDvorak Загружается синхронно, если он не внешний (не имеет src) . В противном случае он будет выполнен "как можно скорее", асинхронно.
Ориоль
1
Это все еще может сломаться, так как Chrome намеренно откажется выполнять document.writeвызовы, которые вставляют <script>теги, если пользователь подключен к сети 2G. См developers.google.com/web/updates/2016/08/...
Флиммы
42

Это может заблокировать вашу страницу

document.writeработает только во время загрузки страницы; Если вы позвоните по окончании загрузки страницы, она перезапишет всю страницу.

Это фактически означает, что вы должны вызывать его из встроенного блока сценария - и это не позволит браузеру обрабатывать последующие части страницы. Скрипты и изображения не будут загружены, пока блок записи не будет завершен.

Шон Макмиллан
источник
32

Pro:

  • Это самый простой способ встроить встроенный контент из внешнего (на ваш хост / домен) сценария.
  • Вы можете перезаписать весь контент в фрейме / фрейме. Раньше я часто использовал эту технику для элементов меню / навигации, прежде чем более современные методы Ajax стали широко доступны (1998-2002).

Против:

  • Он сериализует механизм рендеринга, чтобы сделать паузу до тех пор, пока не будет загружен внешний скрипт, что может занять гораздо больше времени, чем внутренний скрипт
  • Обычно он используется таким образом, что сценарий размещается внутри содержимого, что считается дурным тоном.
Tracker1
источник
3
Есть больше минусов, чем это. Например, Google Chrome откажется от запуска, document.writeкоторый создает <script>тег при определенных обстоятельствах. developers.google.com/web/updates/2016/08/…
Flimm
@Flimm Стоит отметить, ваш комментарий более 8 лет после моего ответа, и это почти 3 года спустя. Да, есть и другие минусы ... и я был бы удивлен, если сам document.write не исчезнет ... а также, возможно, некоторые другие сильно злоупотребляют интерфейсами.
Tracker1
10

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

http://www.quirksmode.org/blog/archives/2005/06/three_javascrip_1.html

Я обнаружил это недавно, пытаясь создать галерею слайдеров AJAX. Я создал два вложенных div и применилwidth / heightи overflow: hiddenк внешнему <div>с помощью JS. Это было сделано для того, чтобы в случае, если в браузере была отключена JS, div будет плавать, чтобы разместить изображения в галерее, что является хорошим грациозным ухудшением.

Дело в том, что, как и в статье выше, это угон JS CSS не срабатывал до тех пор, пока страница не была загружена, вызывая мгновенное мигание при загрузке div. Поэтому мне нужно было написать правило CSS или включить лист, когда страница загружена.

Очевидно, что это не сработает в XHTML, но, поскольку XHTML выглядит как мертвая утка (и отображается как теговый суп в IE), возможно, стоит пересмотреть ваш выбор DOCTYPE ...

sunwukung
источник
7

Он перезаписывает контент на странице, что является наиболее очевидной причиной, но я бы не назвал это «плохой».

Это просто не имеет большого смысла, если вы не создаете весь документ с использованием JavaScript, в этом случае вы можете начать с document.write.

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

aleemb
источник
2
Одно уточнение: document.write вставляет содержимое на страницу, но не перезаписывает его.
Питер Долберг
5
@Peter, он перезаписывает содержимое, если вы вызываете его после загрузки документа. Я предполагаю, что это значит aleemb.
Мэтью Крамли
2
Вы предлагаете вместо этого вручную создавать отдельные узлы DOM в коде, а не делать что-то подобное div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";? Кажется, что это приведет к большому количеству ненужного и менее читаемого кода. Это также полная противоположность подхода, который Джон Резиг и другие разработчики JS защищают.
Lèse Majesté
7

Он разбивает страницы с использованием XML-рендеринга (например, страниц XHTML).

Лучший : некоторые браузеры переключаются обратно на рендеринг HTML, и все работает отлично.

Вероятно : некоторые браузеры отключают функцию document.write () в режиме рендеринга XML.

Хуже всего : некоторые браузеры будут генерировать ошибку XML всякий раз, когда используют функцию document.write ().

Винсент Роберт
источник
6

С верхней части моей головы:

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

  2. Технически document.writeбудут обновляться только HTML-страницы, а не XHTML / XML. IE, кажется, довольно прощает этот факт, но другие браузеры не будут.

http://www.w3.org/MarkUp/2004/xhtml-faq#docwrite

Brendan
источник
9
IE прощает, потому что он не поддерживает XHTML. Если / когда они это сделают, то document.write, вероятно, перестанет работать (конечно, только в XHTML).
Мэтью Крамли
2
XHTML не имеет отношения к сети. Даже страницы со строгим XHTML DOCTYPE фактически не рассматриваются как XML в этой связи, разработчики браузеров не доверяют авторов страниц , что много.
RobG
4

Chrome может блокировать document.writeвставку скрипта в определенных случаях. Когда это произойдет, в консоли отобразится это предупреждение:

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

Ссылки:

TrueWill
источник
3

Нарушение браузера

.writeсчитается нарушением браузера, так как останавливает анализатор от рендеринга страницы. Парсер получает сообщение о том, что документ изменяется; следовательно, он блокируется, пока JS не завершит свой процесс. Только в это время парсер возобновит работу.

Представление

Самым большим последствием использования такого метода является снижение производительности. Браузеру потребуется больше времени для загрузки содержимого страницы. Неблагоприятная реакция на время загрузки зависит от того, что записывается в документ. Вы не увидите большой разницы, если добавите <p>тег в DOM, в отличие от передачи массива из 50 ссылок на библиотеки JavaScript (что я видел в рабочем коде и привело к 11-секундной задержке) Конечно, это также зависит от вашего оборудования).

В общем, лучше избегать этого метода, если вы можете помочь ему.

Для получения дополнительной информации см. Вмешательство против document.write ()

Ариэль Адамс
источник
3

Основываясь на анализе, проведенном компанией Lighthouse Audit от Google-Chrome Dev Tools ,

Для пользователей, использующих медленные соединения, внешние сценарии, динамически внедряемые через, document.write()могут задерживать загрузку страницы на десятки секунд.

введите описание изображения здесь

Судип Бхандари
источник
2
  • Простая причина document.writeплохой практики заключается в том, что вы не можете придумать сценарий, в котором вы не можете найти лучшую альтернативу.
  • Другая причина в том, что вы имеете дело со строками, а не с объектами (это очень примитивно).
  • Это только добавить к документам.
  • Он не имеет ничего общего с красотой, например, шаблона MVC (Model-View-Controller) .
  • Гораздо эффективнее представлять динамический контент с помощью ajax + jQuery или angularJS .
Андерс Линден
источник
Что касается вашей первой пули, как вы собираетесь решить то, что @sunwukung описывает в своем ответе выше? Я согласен, что вы можете решить эту проблему с помощью манипуляций с DOM, но, поскольку манипуляции с DOM идут, трудно избежать FUOC время от времени document.write.
Берт Брюноог
FUOC больше не проблема?
Андерс Линден
1

Можно рассматривать document.write () (и .innerHTML) как оценку строки исходного кода. Это может быть очень удобно для многих приложений. Например, если вы получаете HTML-код в виде строки из какого-то источника, удобно просто «оценить» его.

В контексте Lisp манипулирование DOM было бы похоже на манипулирование структурой списка, например, создание списка (оранжевого цвета) с помощью:

(cons 'orange '())

И document.write () - это как вычисление строки, например, создание списка путем оценки строки исходного кода, например:

(eval-string "(cons 'orange '())")

Lisp также обладает очень полезной способностью создавать код, используя манипуляции со списком (например, используя «стиль DOM» для создания дерева разбора JS). Это означает, что вы можете создать структуру списка, используя «стиль DOM», а не «стиль строки», а затем запустить этот код, например, так:

(eval '(cons 'orange '()))

Если вы реализуете инструменты кодирования, такие как простые живые редакторы, очень удобно иметь возможность быстро оценивать строку, например, используя document.write () или .innerHTML. Lisp идеален в этом смысле, но вы можете делать очень крутые вещи и в JS, и многие люди делают это, например, http://jsbin.com/

Микаэль Киндборг
источник
1

Недостатки document.write в основном зависят от этих 3 факторов:

а) Реализация

Document.write () в основном используется для записи содержимого на экран, как только оно требуется. Это означает, что это происходит где угодно, либо в файле JavaScript, либо внутри тега скрипта в файле HTML. При размещении тега script в любом месте такого HTML-файла плохая идея иметь операторы document.write () внутри блоков сценария, которые переплетаются с HTML внутри веб-страницы.

б) рендеринг

Хорошо спроектированный код в целом возьмет любой динамически сгенерированный контент, сохранит его в памяти, продолжит манипулировать им, пока он проходит через код, прежде чем он, наконец, выплюнет на экран. Таким образом, чтобы повторить последний пункт в предыдущем разделе, рендеринг контента на месте может отображаться быстрее, чем другой контент, на который можно положиться, но он может быть недоступен для другого кода, который, в свою очередь, требует, чтобы контент был представлен для обработки. Чтобы решить эту дилемму, нам нужно избавиться от document.write () и правильно ее реализовать.

в) невозможное манипулирование

Как только это написано, это сделано и закончено. Мы не можем вернуться, чтобы манипулировать этим без подключения к DOM.

user3167857
источник
1

Я не думаю, что использование document.write является плохой практикой вообще. Проще говоря, это как высокое напряжение для неопытных людей. Если вы используете его неправильно, вас готовят. Есть много разработчиков, которые использовали этот и другие опасные методы хотя бы один раз, и они никогда не зацикливаются на своих ошибках. Вместо этого, когда что-то идет не так, они просто выручают и используют что-то более безопасное. Это те, кто делает такие заявления о том, что считается «плохой практикой».

Это похоже на форматирование жесткого диска, когда вам нужно удалить только несколько файлов, а затем сказать «форматирование диска - плохая практика».

Эдгарс Вебхаус
источник
-3

Я думаю, что самая большая проблема заключается в том, что любые элементы, написанные через document.write, добавляются в конец элементов страницы. Это редко желаемый эффект с современными макетами страниц и AJAX. (вы должны помнить, что элементы в DOM являются временными, и когда скрипт запускается, это может повлиять на его поведение).

Намного лучше установить элемент-заполнитель на странице, а затем манипулировать его innerHTML.

BnWasteland
источник
15
Это неправда. document.write не добавляет содержимое в конец страницы, как будто это дополнение. Они написаны на месте.
Питер Бейли
1
@ Питер Бэйли, я знаю, что это старая тема, но на самом деле это не должно быть опровергнуто. добавляется ли он или нет, зависит от того, работает ли document.write () во время загрузки страницы. Если он вызывается из функции после загрузки страницы, то первый document.write () заменит все тело, а последующие вызовы добавятся к нему.
Осьминог
3
@ Осьминог Да, но это косвенно. Он добавляется в этом сценарии только потому, что есть новый документ. Все еще не точно сказать, что «document.write () добавлен». Да, это старый ответ и старый ответ, но я все еще поддерживаю его.
Питер Бейли
Все в порядке. Я говорил неточно. Я бы отредактировал это давно, но ответ на этот вопрос намного лучше. Я хотел бы отметить, что «написано на месте» в равной степени неточно.
BnWasteland