Чому document.write вважається «поганою практикою»?


363

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

Вкажіть нижче свою причину, коли ви заявляєте document.writeяк погану практику.

Відповіді:


243

Кілька більш серйозних проблем:

  • document.write (відтепер DW) не працює в XHTML

  • DW безпосередньо не модифікує DOM, запобігаючи подальшим маніпуляціям (намагаючись знайти докази цього, але в кращому випадку ситуаційний)

  • DW, виконаний після завантаження сторінки, замінить її, або напише нову сторінку, або не працюватиме

  • DW виконує там, де стикається: він не може вводити в задану точку вузла

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

Набагато краще використовувати безпечні та зручні для DOM методи маніпуляції з DOM


39
-1, він абсолютно модифікує DOM. Все інше добре. Хоча я розумію прагнення залежати від структури та методів, які можуть уберегти вас від шкоди, це може бути випадком викидання дитини разом з водою.
cgp

7
FireBug не є справжнім представленням DOM. Це спроба Мозілла розібрати HTML у DOM. У представленні Firebug DOM ви можете повністю розбитий HTML.
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, вважається сумісним.
Пейсьєр

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. Знімок тут .
БМінер

8
@BMiner, якщо ви вставляєте scriptелемент за допомогою маніпуляції з DOM, він завантажується синхронно? Якщо це не так, це не заміна.
Джон Дворак

2
@JanDvorak - хороший момент; при використанні DOM-маніпуляцій браузери, як правило, завантажують сценарій асинхронно. Ви можете використовувати onloadподію DOM, щоб визначити, коли асинхронно завантажений сценарій доступний для використання.
BMiner

1
@JanDvorak Він завантажується синхронно, якщо він не є зовнішнім (не має src) . Інакше він буде виконаний "якнайшвидше", асинхронно.
Oriol

1
Це все-таки може зламатися, оскільки Chrome навмисно відмовляється виконувати document.writeдзвінки, які вставляють <script>теги, якщо користувач перебуває на підключенні 2G. Дивіться developers.google.com/web/updates/2016/08/…
Flimm

42

Це може заблокувати вашу сторінку

document.writeпрацює лише під час завантаження сторінки; Якщо ви зателефонуєте їй після завантаження сторінки, вона перезапише всю сторінку.

Це фактично означає, що вам доведеться викликати його з блоку вбудованого сценарію - і це не дозволить браузеру обробляти частини сторінки, що слідують за ним. Сценарії та зображення не завантажуватимуться, поки блок запису не буде закінчений.


31

Про:

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

Con:

  • Він серіалізує механізм візуалізації, щоб призупинити, поки не буде завантажений зазначений зовнішній скрипт, що може зайняти набагато більше часу, ніж внутрішній скрипт.
  • Зазвичай він використовується таким чином, що скрипт розміщується всередині вмісту, який вважається поганим.

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. Я створив два вкладені діви та застосував width/ heightта overflow: hiddenдо зовнішнього за <div>допомогою JS. Це було так, що у випадку, якщо браузер відключив JS, div попливе для розміщення зображень у галереї - якась приємна витончена деградація.

Справа в тому, як і у статті вище, цей JS-викрадення CSS не запускався, поки сторінка не завантажилася, викликаючи миттєвий спалах, коли завантажувався div. Тому мені потрібно було написати правило CSS або включити аркуш, як завантажувана сторінка.

Очевидно, що це не буде працювати в XHTML, але оскільки XHTML, здається, є чимось мертвою качкою (і відображається як суп з тегами в IE), можливо, варто переоцінити ваш вибір ДОКТОПУ ...


7

Він перезаписує вміст сторінки, що є найбільш очевидною причиною, але я б не назвав це "поганим".

Він просто не має великої користі, якщо ви не створюєте весь документ за допомогою JavaScript, і в цьому випадку ви можете почати з document.write.

Тим не менш, ти не дуже використовуєш DOM, коли використовуєш document.write - ти просто скидаєш фрагмент тексту в документ, тому я б сказав, що це погана форма.


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


9
IE прощає, оскільки не підтримує XHTML. Якщо / коли вони будуть робити, document.write, ймовірно, перестане працювати (звичайно, лише в XHTML).
Меттью Крамлі

2
XHTML не має значення в Інтернеті. Навіть сторінки зі строгим доктрипом XHTML насправді не трактуються як XML в цьому плані, розробники браузерів не довіряють авторам сторінок, що багато.
RobG

4

Chrome може блокувати, document.writeщо вставляє сценарій у певних випадках. Коли це станеться, воно з’явиться на консолі:

Через document.write викликається скрипт перехресного блокування, ... Цей веб-переглядач може бути заблокований, якщо пристрій погано підключається до мережі.

Список літератури:


3

Порушення веб-переглядача

.writeвважається порушенням браузера, оскільки він зупиняє аналізатор від надання сторінки. Аналізатор отримує повідомлення про те, що документ змінюється; отже, він блокується, поки JS не завершить свій процес. Лише в цей час аналізатор відновиться.

Продуктивність

Найбільшим наслідком використання такого методу є зниження продуктивності. Для завантаження вмісту сторінки у веб-переглядача знадобиться більше часу. Побічна реакція на час завантаження залежить від того, що написано в документі. Ви не побачите великої різниці, якщо ви додасте <p>тег до DOM на відміну від передачі масиву з 50-ти посилань на бібліотеки JavaScript (те, що я бачив у робочому коді і призвело до затримки на 11 секунд - з Звичайно, це також залежить від вашого обладнання).

Загалом, найкраще уникати цього методу, якщо ви зможете в цьому допомогти.

Для отримання додаткової інформації див. Втручання проти document.write ()


3

На основі аналізу, проведеного аудитом маяків Dev Tools « Маяк» ,

Для користувачів на повільних з'єднаннях зовнішні сценарії, динамічно введені через, document.write()можуть затримати завантаження сторінки на десятки секунд.

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


2
  • Проста причина, чому document.writeце погана практика, полягає в тому, що ви не можете придумати сценарій, коли не можете знайти кращої альтернативи.
  • Ще одна причина полягає в тому, що ви маєте справу з рядками замість об’єктів (це дуже примітивно).
  • Він додає лише до документів.
  • Він не має нічого красного, наприклад, модель MVC (Model-View-Controller) .
  • Набагато потужніше представляти динамічний контент за допомогою ajax + jQuery або angularJS .

Що стосується вашої першої кулі, як ви вирішите вирішити те, що @sunwukung описує у своїй відповіді вище? Я погоджуюся, що ви могли це вирішити за допомогою маніпуляцій DOM, але в міру маніпуляцій з DOM важко уникнути FUOC часом document.write.
bert bruynooghe

Чи FUOC вже є проблемою?
Anders Lindén

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-файлі. Оскільки тег сценарію розміщується в будь-якому місці такого HTML-файлу, погана ідея мати висловлювання document.write () всередині блоків сценаріїв, які переплітаються з HTML всередині веб-сторінки.

б) Надання

Добре розроблений код взагалі буде приймати будь-який динамічно генерований контент, зберігати його в пам'яті, продовжувати маніпулювати ним, коли він проходить через код, перш ніж він нарешті вийде на екран. Отже, щоб повторити останню точку в попередньому розділі, візуалізація вмісту на місці може відображатися швидше, ніж інший вміст, на який можна покластися, але він може бути недоступний для іншого коду, який, у свою чергу, вимагає, щоб вміст був наданий на обробку. Для вирішення цієї дилеми нам потрібно позбутися документа.write () та реалізувати його правильним способом.

в) Неможливий маніпуляції

Як тільки це буде написано, це зроблено і закінчено. Ми не можемо повернутися, щоб маніпулювати нею, не потрапивши в DOM.


1

Я не думаю, що використання document.write зовсім погана практика. Простими словами - це як висока напруга для недосвідчених людей. Якщо ви вживаєте його неправильно, ви готуєтесь. Є багато розробників, які використовували цей та інші небезпечні методи хоча б один раз, і вони ніколи насправді не копаються у своїх невдачах. Натомість, коли щось піде не так, вони просто рятують і використовують щось безпечніше. Це ті, хто робить такі заяви про те, що вважається "поганою практикою".

Це як форматування жорсткого диска, коли потрібно видалити лише кілька файлів, а потім сказати, що "форматування диска - це погана практика".


-3

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

Набагато краще встановити на сторінці елемент-заповнювач, а потім маніпулювати його внутрішнім HTML.


15
Це не правда. document.write не додає вміст у кінець сторінки, як-от додаток. Вони написані на місці.
Пітер Бейлі

1
@Peter Bailey, я знаю, що це стара тема, але насправді це не слід сприймати. додає він чи ні, залежить від того, чи document.write () працює в рядку під час завантаження сторінки. Якщо він викликається з функції після завантаження сторінки, то перший document.write () замінить все тіло і наступні дзвінки додаватимуться до нього.
Восьминіг

3
@ Октопод Так, але це навмисно. Він додається до цього сценарію лише тому, що є свіжий документ. Ще не точно сказати "document.write () додає". Так, це стара відповідь і старий голос, але я все одно стою його.
Пітер Бейлі

Це добре. Я говорив неточно. Я б це давно редагував, але вище є набагато краща відповідь. Я хотів би зазначити, що те, що "написано на місці", не менш точне.
BnWasteland
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.