Есть ли прирост производительности при добавлении тегов <script>по сравнению с использованием eval? - PullRequest
12 голосов
/ 05 декабря 2011

Я видел много предложений о том, как нужно динамически добавлять код, например: (источник) :

var myScript = document.createElement("script");
myScript.setAttribute("type","text/javascript");
myScript.innerHTML += 'alert("Hello");';
document.body.appendChild(myScript);

В отличие от eval, например,

eval('alert("Hello");');

Люди жалуются на снижение производительности и проблемы безопасности с eval, но я не могу представить, как добавление тегов <script> будет быстрее или безопаснее.


РЕДАКТИРОВАТЬ люди хотели бы знать, почему я оцениваю нечто столь же тривиальное, как alert("Hello"), вот почему:

У меня есть база данных, позволяетскажем, 1,000,000,000,000 сценариев = P, очевидно, я не могу загрузить каждый, вместо этого пользователь может загружать все, что пожелает.Скрипты хранятся на стороне сервера в произвольных местах.В настоящее время я запрашиваю (xmlhttprequest, интерпретируемый как javascript) скрипт через его имя скрипта, и сервер найдет его (каким-то образом) и вернет его в виде текста, который сразу же будет выполнен / интерпретирован.Я хочу знать, будет ли лучше вернуть скрипт в виде текста, а затем создать из него тег <script>.

Кроме того, это НЕ дубликат Разница в JavaScript между eval () и добавлением тегов сценария , которая касается функциональных различий, здесь я хочу различия в производительности и безопасности.

Ответы [ 5 ]

7 голосов
/ 05 декабря 2011

Нет, при использовании тегов <script> прирост производительности отсутствует, в отличие от eval. В двух приведенных вами примерах eval намного быстрее во всех протестированных мной браузерах. Отчасти разница в том, что с <script>, помимо запуска скрипта, он модифицирует DOM, но это еще не все. При использовании более длинных сценариев разница не столь выражена, но eval все же быстрее:

ОБНОВЛЕНИЕ: я обновил демо, чтобы лучше соответствовать тестам лицом к лицу (оба сейчас создают script блоков). Результаты по-прежнему показывают eval намного быстрее.

jsPerf: http://jsperf.com/stackoverflow-8380204-eval-vs-script

enter image description here

Таким образом, причины не использовать eval связаны только с безопасностью. Из принятого ответа на Почему использование функции eval в JavaScript - плохая идея? :

  1. Неправильное использование eval открывает ваш код для инъекционных атак
  2. Отладка может быть более сложной (без номеров строк и т. Д.)

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

В качестве отступления: на основании вашего шаблона использования в конце вашего вопроса вы можете проверить require.js для динамической загрузки скриптов.

2 голосов
/ 05 декабря 2011

Вы понимаете, что делаете две разные вещи.

"eval" -> запустить интерпретатор JS, интерпретировать и запустить код js.

"script" -> заставить DOM создать и внедрить узел сценария, затем запустить интерпретатор JS, интерпретировать и запустить код js.

По сути, браузер делает то же самое, что и eval.У вас просто есть издержки на создание и внедрение узла в DOM

2 голосов
/ 05 декабря 2011

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

ПростоПримечание;код, переданный в 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.
})();

Обратите внимание, что это отличается от вашего кода, в этомэто загружает скрипт с сервера, вместо того, чтобы писать Javascript непосредственно в элемент.Честно говоря, я не могу представить, почему вы захотите сделать это, если вместо этого вы можете просто загрузить файл удаленно.

0 голосов
/ 04 сентября 2016

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

Многие комментарии ставят под сомнение мотивацию ОП, которая является действительной.

Мой пример использования решает эту проблемунужно ... Я хочу загрузить код JS с сервера, но это не http-сервер.Клиент (браузер) подключается через веб-сокет и синхронизируется с чем-то вроде серверной DOM.

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

Эти фрагменты кода также могут иметь зависимости, поэтому я пишу плагин веб-сокета для require.js дляудовлетворить их .... Некоторые части могут быть статическими файлами, обслуживаемыми через httpd, но другие могут генерироваться динамически на основе пользовательских списков ACL.

Итак ... Лучший способ внедрения в браузер по-прежнему неясен в этой теме.Некоторые утверждают, что с eval () все в порядке, но добавление тега script с innerText - это другой способ.Другая идея состоит в том, чтобы b64 кодировать значение src тега сценария.

Где-то в Интернете упоминалось, что динамически внедряемый код не извлекает выгоду из определенных оптимизаций кода в v8 и несет значительную потерю производительности.Базовое «предупреждение (« Привет, мир »);»вероятно, не раскрыть это.Насколько я понимаю, JIT-компилятор для v8 и, вероятно, другие не тратят это время на оптимизацию, потому что обычно eval () для тривиальных битов кода.

0 голосов
/ 05 декабря 2011

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

В случае eval скорость синтаксического анализа и выполнения (возможно) равна синтаксическому анализу нового тега сценария, и переданная строка может быть освобождена из памяти после завершения.

Что касается безопасностиЯ думаю, он может включать вредоносный код в ваш eval, вы также можете включить его в тег script.

В любом случае, избегайте того, что и другое, как говорит @jergason, оба одинаково плохи.

...