Каковы плюсы и минусы добавления элементов <script> и <link> с использованием JavaScript?

Недавно я увидел некоторый HTML с единственным элементом <script> в своем <head>...

<head>
    <title>Example</title>
    <script src="script.js" type="text/javascript"></script>
    <link href="plain.css" type="text/css" rel="stylesheet" />
</head>

Затем script.js добавляет в документ любые другие необходимые элементы <script> и <link>, используя document.write(...): (или он может использовать document.createElement(...) и т.д.)

document.write("<link href=\"javascript-enabled.css\" type=\"text/css\" rel=\"styleshet\" />");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js\" type=\"text/javascript\"></script>");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js\" type=\"text/javascript\"></script>");
document.write("<link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/trontastic/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" />")
document.write("<script src=\"validation.js\" type=\"text/css\"></script>")

Обратите внимание, что в документе <head> и script.js есть файл plain.css CSS, который добавляет все CSS и JavaScript, которые будут использоваться пользовательским агентом с поддержкой JS.

Каковы некоторые из плюсов и минусов этой техники?

Ответ 1

Блокирующий характер document.write

document.write остановит все, что браузер работает на странице (включая синтаксический анализ). Настоятельно рекомендуется избегать из-за этого поведения блокировки. В браузере нет способа узнать, что вы собираетесь вставлять в текстовый поток HTML в этот момент, или будет ли запись полностью уничтожать все в дереве DOM, поэтому она должна остановиться, пока вы не закончите.

По сути, загрузка скриптов таким образом заставит браузер перестать анализировать HTML. Если ваш script находится в строке, браузер также выполнит эти сценарии до его продолжения. Поэтому в качестве побочного примечания всегда рекомендуется отложить загрузку скриптов до тех пор, пока ваша страница не будет проанализирована, и вы продемонстрировали пользователю разумный пользовательский интерфейс.

Если ваши скрипты загружаются из отдельных файлов в атрибуте "src", тогда сценарии могут не выполняться последовательно во всех браузерах.

Утрата оптимизаций и предсказуемости скорости браузера

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

Например, некоторые браузеры будут запускать скрипты сразу после их "записи". В таких случаях вы теряете параллельную загрузку скриптов (потому что браузер не видит второй тег script, пока он не скачал и не выполнил первый). Вы теряете параллельные загрузки скриптов и таблиц стилей и других ресурсов (многие браузеры могут одновременно загружать ресурсы, таблицы стилей и скрипты).

Некоторые браузеры откладывают скрипты до тех пор, пока они не будут выполнены.

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

Другими словами, ваш сайт стал таким же медленным, как и загрузка на многолетнем браузере без оптимизации.

Зачем кому-то это делать?

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

Проблема заключается в том, что JavaScript не имеет оператора @include или @import для включения других файлов.

Некоторые решения

Решение этого, вероятно, не путем ввода скриптов через document.write, а путем:

  • Использование директив @import в таблицах стилей
  • Использование языка сценариев сервера (например, PHP) для управления вашей "главной страницей" и для создания всех других страниц (однако, если вы не можете использовать это и должны поддерживать много HTML-страниц отдельно, это не решение)
  • Избегайте document.write, но загружайте файлы JavaScript через XHR, затем eval() - это может иметь проблемы с безопасностью, хотя
  • Используйте библиотеку JavaScript (например, Dojo), которая имеет функции загрузки модуля, чтобы вы могли хранить главный файл JS, который загружает другие файлы. Вы не сможете избежать обновления номеров версий файла библиотеки, хотя...

Ответ 2

Одним из основных недостатков является несовместимость браузера. Не все браузеры правильно извлекают и включают ресурсы в DOM, поэтому рискованно использовать этот подход. Это более верно для таблиц стилей, чем скриптов.

Другая проблема - это ремонтопригодность. Конкатенация и запись строк для добавления элементов DOM на стороне клиента может стать кошмаром для обслуживания. Лучше использовать DOM-методы, такие как createElement, для семантического создания элементов.

Одним очевидным преимуществом является то, что он облегчает условное использование ресурсов. У вас может быть логика, которая определяет, какие ресурсы загружаться, тем самым уменьшая потребление полосы пропускания и общее время обработки страницы. Я бы использовал вызов библиотеки, такой как jQuery $.getScript(), для загрузки скриптов и document.write. Преимущество заключается в том, что такой подход является более чистым, а также позволяет выполнять код, когда запрос завершен или не выполняется.

Ответ 3

Хорошо, я тоже могу бросить свою шляпу в кольцо на этом...

Если вы изучите библиотеку закрытия google, base.js, вы увидите, что document.write используется в их функции writeScriptTag_(). Это неотъемлемая часть системы управления зависимостями, которую обеспечивает "закрытие", и является огромным преимуществом при создании сложного, многофайлового, основанного на библиотеке приложения javascript - это позволяет предварительным условиям файла/кода определять порядок загрузки. В настоящее время мы используем эту технику и с ней мало проблем. TBH, у нас не было ни одной проблемы с совместимостью с браузерами, и мы регулярно тестируем теги IE 6/7/8, FF3/2, Safari 4/5 и Chrome.

Единственный недостаток, который у нас был до сих пор, заключается в том, что может быть сложно выявить проблемы, связанные с загрузкой ресурса в два раза или с невозможностью загрузить его вообще. Поскольку действие загрузки ресурсов является программным, оно подвержено программным ошибкам, и в отличие от добавления тегов непосредственно в HTML, может быть трудно понять, что такое точный порядок загрузки. Однако эту проблему можно в значительной степени преодолеть, используя библиотеку с некоторой формой системы управления зависимостями, например закрытие, или dojo.

EDIT: Я сделал несколько замечаний по этому поводу, но я подумал, что лучше всего подвести итог в моем ответе: Существуют некоторые проблемы с dojo.require() и jQuery.getScript() (оба из которых одновременно выполняют запрос ajax и eval).

  • Загрузка через ajax означает отсутствие перекрестных скриптов - то есть без загрузки javascript, который не с вашего сайта. Это будет проблемой, если вы хотите включить https://ajax.googleapis.com, как указано в описании.
  • Скрипты Eval'd не будут отображаться в списке сценариев отладки javascript, что делает отладки довольно сложной. Последние выпуски firebug покажут вам код eval'd, однако имена файлов будут потеряны, что приведет к утомительному установлению контрольных точек. AFAIK, консоль javascript Webkit и инструменты разработчика IE8 не показывать сценарии eval'd.

Ответ 4

Это имеет то преимущество, что вам не нужно повторять ссылки script в каждом файле HTML. Недостатком является то, что браузер должен извлечь и выполнить основной файл javascript, прежде чем он сможет загрузить остальные.

Ответ 5

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

Ответ 6

В Google PageSpeed ​​они сильно препятствуют вам использовать эту технику, потому что это замедляет работу. Помимо последовательной загрузки ваших script.js перед всеми остальными, появляется еще один catch:

Современные браузеры используют спекулятивные синтаксические анализаторы для более эффективного обнаружения внешних ресурсов [...] Таким образом, использование JavaScript document.write() для извлечения внешних ресурсов делает невозможным, чтобы спекулятивный анализатор обнаруживал эти ресурсы, что может задержать загрузку, синтаксический анализ и рендеринг этих ресурсов.

Ответ 7

Также возможно, что это было написано как рекомендация фирмы SEO, чтобы сделать элемент главы короче, если это возможно, поэтому уникальный контент ближе к верхней части документа, что также создает более высокое соотношение текста и HTML. Хотя это звучит, все в целом, как не очень хороший способ сделать это; хотя это сделало бы обслуживание более трудоемким, лучше всего было бы скомпоновать javascript в один файл .js и css в один .css файл, если бы было сочтено необходимым уменьшить размер элемента заголовка.

Ответ 8

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

В настоящее время рекомендуется помещать теги script вправо befo </body>. Конечно, это невозможно в 100% случаев, но если вы используете unobtrusve Javascript (как и должно быть), все сценарии могут быть перенесены в конец документа.

В HTML5 появился атрибут async, который предлагает браузеру только выполнить сценарии после загрузки основного документа. Это поведение вложенных скриптов script во многих браузерах, но не во всех них.

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

И да, как упоминалось ранее, если сценарий отключен, ваша страница будет показана без CSS (что делает ее потенциально непригодной для использования).

Ответ 9

  • Если JavaScript отключен - <script> and <link>, элементы не будут добавлены вообще.

  • Если вы помещаете функции инициализации JavaScript в нижней части страницы (что является хорошей практикой) и связываете CSS с JavaScript, это может вызвать некоторую задержку перед загрузкой CSS (сломанный макет будет отображаться в течение короткого времени).