Есть ли увеличение производительности, включая теги <script>, а не использование eval?
Я видел много предложений о том, как динамически добавлять код так: (источник):
var myScript = document.createElement("script");
myScript.setAttribute("type","text/javascript");
myScript.innerHTML += 'alert("Hello");';
document.body.appendChild(myScript);
В отличие от eval
так
eval('alert("Hello");');
Люди жалуются на снижение производительности и проблемы с безопасностью с помощью eval
, но я не могу себе представить, как добавление тегов <script>
будет быстрее или безопаснее.
EDIT люди хотели бы знать, почему я угадываю что-то как тривиальное, как alert("Hello")
, вот почему:
У меня есть база данных, скажем, 1 000 000 000 000 скриптов = P, очевидно, я не могу загрузить каждый, вместо этого пользователь может загружать все, что пожелает. Сценарии хранятся на серверах в произвольных местах. В настоящее время я запрашиваю (xmlhttprequest интерпретируется как javascript) script через его имя script, и сервер найдет его (каким-то образом) и вернет его как текст, который сразу же будет выполнен/интерпретирован. Я хочу знать, было бы лучше вернуть текст script в качестве текста, а затем создать тэг <script>
.
Кроме того, это НЕ дубликат разницы в JavaScript между eval() и добавлением тегов script, который касается функциональных различий, здесь я хочу, чтобы производительность и различия в безопасности.
Ответы
Ответ 1
Нет, нет увеличения производительности с использованием тегов <script>
, а не с помощью eval
. В двух образцах, которые вы дали, eval
намного быстрее во всех проверенных вами браузерах. Отличие состоит в том, что при <script>
, помимо запуска script, он модифицирует DOM, но это не все. С более длинными сценариями разница не столь выражена, но eval
все еще быстрее:
UPDATE: я обновил демоверсию, чтобы лучше совместить тесты "голова к голове" (оба теперь создают блоки script
). Результаты по-прежнему показывают eval
намного быстрее.
jsPerf: http://jsperf.com/stackoverflow-8380204-eval-vs-script
![enter image description here]()
Таким образом, причины не использовать eval
связаны только с безопасностью. Из принятого ответа на Почему использование JavaScript eval-функции - плохая идея?:
- Неправильное использование eval открывает ваш код для инъекционных атак.
- Отладка может быть более сложной (нет номеров строк и т.д.).
Есть третий, который говорит о скорости, но он опровергается в комментариях к этому ответу. Если вы не можете гарантировать источник сценариев, которые вы планируете eval
, его следует избегать.
В стороне: на основе вашего шаблона использования в конце вашего вопроса вы можете проверить require.js для динамического загрузки сценариев.
Ответ 2
Это, вероятно, один из тех дебатов, которые меняются в зависимости от браузера, и мнение программиста. Я бы не представлял себе существенной разницы в производительности между этими двумя подходами, если вы не делаете такие вещи много раз (и даже тогда это, вероятно, было бы показательно, если проблема дизайна).
Просто боковое примечание; код, переданный в eval()
, может быть особенно сложным для отладки и не может быть кэширован так же, как асинхронная загрузка JavaScript может:
(function() {
var s = document.createElement('script');
s.async = true; // HTML5
s.type = 'text/javascript';
s.src = 'http://example.com/application.js';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
// can be added to the body element as well, which may be better.
})();
Обратите внимание, что это отличается от вашего кода, тем самым он загружает script с сервера, вместо того, чтобы писать Javascript непосредственно в элемент. Честно говоря, я не могу представить, почему вы хотите сделать это, когда вы можете просто загрузить файл удаленно.
Ответ 3
Вы понимаете, что делаете две разные вещи.
"eval" → запустить JS-интерпретатор, интерпретировать и запустить js-код.
"script" → получить DOM для создания и ввода script node, затем запустить JS-интерпретатор, интерпретировать и запустить js-код.
В основном браузер делает то же самое, что и eval. У вас просто есть накладные расходы на создание и впрыскивание node в DOM
Ответ 4
Я думаю, что eval лучше, если вы создадите новый элемент и напишите его до конца тела, браузер никогда не выпустит эту память, пока существует тег script, и это каким-то образом повлияет на общую производительность.
В случае eval скорость для синтаксического анализа и выполнения (возможно) равна разыскиваемому новому тегу script, и передаваемая строка, возможно, будет выпущена из памяти по завершении.
Что касается безопасности, я думаю, что это может включать вредоносный код в ваш eval, вы также можете включить его в тег script.
Во всяком случае, избегайте обоих, как говорит @jergason, так же плохо.
Ответ 5
Я наткнулся на этот разговор, пытаясь решить подобную проблему.
Многие комментарии задают вопрос о том, каковы мотивы OPs, которые действительны.
Мой вариант использования адресован этой необходимости... Я хочу загрузить JS-код с сервера, но это не http-сервер. Клиент (браузер) подключается через websocket и синхронизируется с чем-то вроде DOM на стороне сервера.
Но узлы сервера DOM могут захотеть выдать JavaScript-код пользователю для управления этими узлами. Этот код хочет проникнуть через websocket, но тогда вопрос заключается в том, как ввести его в браузер.
Эти фрагменты кода также могут иметь зависимости, поэтому я пишу плагин websocket для require.js для их удовлетворения.... Некоторые части могут быть статическими файлами, обслуживаемыми через httpd, но другие могут быть динамически созданы на основе пользователя списки управления доступом.
Итак... Лучший способ впрыска в браузер по-прежнему не ясен из этой темы. Некоторые утверждают, что eval() в порядке, но добавление тега script с innerText является другим способом. Другая идея - b64 закодировать значение src тега script.
В Интернете упоминалось, что динамически вставляемый код не выигрывает от определенных оптимизаций кода в v8 и страдает значительной потерей производительности. Основное "предупреждение" ( "мир привет" ); вероятно, не обнаружит этого. Я понимаю, что компилятор JIT для v8 и, предположительно, другие, не тратит это время оптимизации, потому что обычно eval() для тривиальных бит кода.