Как я могу ссылаться на тег script, который загружает выполняемый в настоящее время script?

Как я могу ссылаться на элемент script, который загружал javascript, который в настоящее время работает?

Вот ситуация. У меня есть "master" script, загружаемый с высокой скоростью на страницу, прежде всего под тегом HEAD.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="scripts.js"></script>

В "scripts.js" есть script, который должен иметь возможность выполнять загрузку других скриптов по требованию. Обычный метод не работает для меня, потому что мне нужно добавить новые скрипты, не ссылаясь на тег HEAD, потому что элемент HEAD не закончил рендеринг:

document.getElementsByTagName('head')[0].appendChild(v);

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

<script type="text/javascript" src="scripts.js"></script>
loaded by scripts.js--><script type="text/javascript" src="new_script1.js"></script>
loaded by scripts.js --><script type="text/javascript" src="new_script2.js"></script>

Ответ 1

Как получить текущий элемент скрипта:

1. Используйте document.currentScript

document.currentScript вернет элемент <script>, скрипт которого в данный момент обрабатывается.

<script>
var me = document.currentScript;
</script>

Преимущества

  • Просто и понятно. Надежный.
  • Не нужно изменять тег сценария
  • Работает с асинхронными сценариями (defer и async)
  • Работает со скриптами, вставляемыми динамически

Проблемы

  • Не будет работать в старых браузерах и IE.
  • Не работает с модулями <script type="module">

2. Выберите скрипт по идентификатору

Предоставив сценарию атрибут id, вы сможете легко выбрать его по идентификатору изнутри, используя document.getElementById().

<script id="myscript">
var me = document.getElementById('myscript');
</script>

Преимущества

  • Просто и понятно. Надежный.
  • Почти повсеместно поддерживается
  • Работает с асинхронными сценариями (defer и async)
  • Работает со скриптами, вставляемыми динамически

Проблемы

  • Требуется добавить пользовательский атрибут в тег скрипта
  • Атрибут id может вызвать странное поведение для скриптов в некоторых браузерах для некоторых крайних случаев

3. Выберите сценарий, используя атрибут data-*

Придание сценарию атрибута data-* позволит вам легко выбрать его изнутри.

<script data-name="myscript">
var me = document.querySelector('script[data-name="myscript"]');
</script>

Это имеет несколько преимуществ по сравнению с предыдущим вариантом.

Преимущества

  • Просто и понятно.
  • Работает с асинхронными сценариями (defer и async)
  • Работает со скриптами, вставляемыми динамически

Проблемы

  • Требуется добавить пользовательский атрибут в тег скрипта
  • HTML5 и querySelector() не совместимы во всех браузерах
  • Менее широко поддерживается, чем использование атрибута id
  • Обойдем <script> с помощью id краевых корпусов.
  • Может запутаться, если другой элемент имеет такой же атрибут данных и значение на странице.

4. Выберите скрипт по src

Вместо использования атрибутов данных вы можете использовать селектор для выбора сценария по источнику:

<script src="//example.com/embed.js"></script>

В embed.js:

var me = document.querySelector('script[src="//example.com/embed.js"]');

Преимущества

  • Расписание
  • Работает с асинхронными сценариями (defer и async)
  • Работает со скриптами, вставляемыми динамически
  • Не требуется никаких пользовательских атрибутов или идентификатора

Проблемы

  • не работает для локальных сценариев
  • Вызывает проблемы в разных средах, таких как разработка и производство
  • Статичный и хрупкий. Изменение местоположения файла скрипта потребует модификации скрипта
  • Менее широко поддерживается, чем использование атрибута id
  • Это вызовет проблемы, если вы дважды загрузите один и тот же скрипт

5. Просмотрите все сценарии, чтобы найти тот, который вам нужен

Мы также можем перебрать каждый элемент скрипта и проверить каждый отдельно, чтобы выбрать тот, который мы хотим:

<script>
var me = null;
var scripts = document.getElementsByTagName("script")
for (var i = 0; i < scripts.length; ++i) {
    if( isMe(scripts[i])){
      me = scripts[i];
    }
}
</script>

Это позволяет нам использовать оба предыдущих метода в старых браузерах, которые не поддерживают querySelector() с атрибутами. Например:

function isMe(scriptElem){
    return scriptElem.getAttribute('src') === "//example.com/embed.js";
}

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

6. Получить последний выполненный скрипт

Поскольку сценарии выполняются последовательно, последний элемент сценария очень часто будет текущим сценарием:

<script>
var scripts = document.getElementsByTagName( 'script' );
var me = scripts[ scripts.length - 1 ];
</script>

Преимущества

  • Простой.
  • Почти повсеместно поддерживается
  • Не требуется никаких пользовательских атрибутов или идентификатора

Проблемы

  • не не работает с асинхронными сценариями (defer и async)
  • не работает со сценариями, вставленными динамически

Ответ 2

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

var scripts = document.getElementsByTagName( 'script' );
var thisScriptTag = scripts[ scripts.length - 1 ];

Ответ 3

Вероятно, самой простой задачей было бы дать вашему тегу scrip атрибут id.

Ответ 4

Скрипт выполняется последовательно, только если у них нет атрибута "отложить" или "асинхронный". Знание одного из возможных атрибутов ID/SRC/TITLE тега скрипта также может работать в этих случаях. Поэтому предложения Грега и Джастина верны.

В списке WHATWG уже есть предложение для document.currentScript.

EDIT: Firefox > 4 уже реализует это очень полезное свойство, но он недоступен в IE11, который последний раз я проверял и доступен только в Chrome 29 и Safari 8.

EDIT. Никто не упомянул коллекцию "document.scripts", но я считаю, что следующая может быть хорошей альтернативой кросс-браузера, чтобы получить текущую версию script:

  var me = document.scripts [document.scripts.length -1];
Код>

Ответ 5

Здесь немного polyfill, который использует document.CurrentScript, если он существует, и возвращается к поиску script по идентификатору.

<script id="uniqueScriptId">
    (function () {
        var thisScript = document.CurrentScript || document.getElementByID('uniqueScriptId');

        // your code referencing thisScript here
    ());
</script>

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

Неподтвержденный, так что оставляйте отзывы для других, если вы попробуете.

Ответ 6

Слово предупреждения: изменение DOM во время его погрузки приведет к миру ранений в IE6 и IE7.

Вам будет лучше запускать этот код после загрузки страницы.

Ответ 7

Он должен работать при загрузке страницы и при добавлении тега script с помощью javascript (например, с ajax)

<script id="currentScript">
var $this = document.getElementById("currentScript");
$this.setAttribute("id","");
//...
</script>

Ответ 8

Следуйте этим простым шагам, чтобы получить ссылку на текущий исполняемый блок script:

  • Поместите некоторую случайную уникальную строку в блок script (должны быть уникальными/разными в каждом блоке script)
  • Итерация результата document.getElementsByTagName('script'), поиск уникальной строки из каждого из их содержимого (полученного из свойства innerText/textContent).

Пример (ABCDE345678 - уникальный идентификатор):

<script type="text/javascript">
var A=document.getElementsByTagName('script'),i=count(A),thi$;
for(;i;thi$=A[--i])
  if((thi$.innerText||thi$.textContent).indexOf('ABCDE345678'))break;
// Now thi$ is refer to current script block
</script>

btw, для вашего случая вы можете просто использовать старомодный метод document.write() для включения другого script. Поскольку вы упомянули, что DOM пока не отображается, вы можете воспользоваться тем фактом, что браузер всегда выполняет script в линейной последовательности (за исключением отложенного, который будет отображаться позже), поэтому остальная часть вашего документа по-прежнему "не существует" ". Все, что вы пишете через document.write(), будет размещено сразу после вызывающего script.

Пример исходной HTML-страницы:

<!doctype html>
<html><head>
<script src="script.js"></script>
<script src="otherscript.js"></script>
<body>anything</body></html>

Содержимое script.js:

document.write('<script src="inserted.js"></script>');

После визуализации структура DOM станет:

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY

Ответ 9

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

function getCurrentScript(callback) {
  if (document.currentScript) {
    callback(document.currentScript);
    return;
  }
  var scripts = document.scripts;
  function onLoad() {
    for (var i = 0; i < scripts.length; ++i) {
      scripts[i].removeEventListener('load', onLoad, false);
    }
    callback(event.target);
  }
  for (var i = 0; i < scripts.length; ++i) {
    scripts[i].addEventListener('load', onLoad, false);
  }
}

getCurrentScript(function(currentScript) {
  window.console.log(currentScript.src);
});

Ответ 10

Чтобы получить script, который в настоящий момент загружает скрипт, вы можете использовать

  var thisScript = document.currentScript;
Код>

Вам нужно сохранить ссылку в начале вашего script, так что вы можете позвонить позже

  var url = thisScript.src
Код>

Ответ 11

Рассмотрим этот алгоритм. Когда ваш script загружается (если есть несколько идентичных скриптов), просмотрите document.scripts, найдите первый script с правильным атрибутом src и сохраните его и пометьте как "посещенный" атрибутом данных или уникальное имя класса.

Когда следующий script загружается, снова сканируйте document.scripts, передавая любой script, уже отмеченный как посещенный. Возьмите первый невидимый экземпляр этого script.

Это предполагает, что идентичные сценарии, скорее всего, выполняются в том порядке, в котором они загружаются, от головы до тела, сверху вниз, от синхронного до асинхронного.

(function () {
  var scripts = document.scripts;

  // Scan for this data-* attribute
  var dataAttr = 'data-your-attribute-here';

  var i = 0;
  var script;
  while (i < scripts.length) {
    script = scripts[i];
    if (/your_script_here\.js/i.test(script.src)
        && !script.hasAttribute(dataAttr)) {

        // A good match will break the loop before
        // script is set to null.
        break;
    }

    // If we exit the loop through a while condition failure,
    // a check for null will reveal there are no matches.
    script = null;
    ++i;
  }

  /**
   * This specific your_script_here.js script tag.
   * @type {Element|Node}
   */
  var yourScriptVariable = null;

  // Mark the script an pass it on.
  if (script) {
    script.setAttribute(dataAttr, '');
    yourScriptVariable = script;
  }
})();

Это сканирует все script для первого сопоставления script, не помеченного специальным атрибутом.

Затем отметьте, что node, если найдено, с атрибутом data, поэтому последующие проверки не будут выбирать его. Это похоже на алгоритмы BFS и DFS с обходным трафиком, где узлы могут быть помечены как "посещенные", чтобы предотвратить повторное использование.

Ответ 12

Если вы можете считать имя файла script, вы можете его найти. До сих пор я только что протестировал следующую функцию в Firefox.

  function findMe(tag, attr, file) {
    var tags = document.getElementsByTagName(tag);
    var r = new RegExp(file + '$');
    for (var i = 0;i < tags.length;i++) {
      if (r.exec(tags[i][attr])) {
        return tags[i][attr];
      }
    }
  };
  var element = findMe('script', 'src', 'scripts.js');

Ответ 13

Существует еще один простой способ, если вы знаете имя сценария (или, по крайней мере, его часть):

document.querySelector('script[src*="<scriptname>.js"]')

Это также будет работать в IE11.

Ответ 14

У меня есть это, которое работает в FF3, IE6 и 7. Методы в загружаемых сценариях по запросу недоступны до тех пор, пока загрузка страницы не будет завершена, но это все еще очень полезно.

//handle on-demand loading of javascripts
makescript = function(url){
    var v = document.createElement('script');
    v.src=url;
    v.type='text/javascript';

    //insertAfter. Get last <script> tag in DOM
    d=document.getElementsByTagName('script')[(document.getElementsByTagName('script').length-1)];
    d.parentNode.insertBefore( v, d.nextSibling );
}

Ответ 15

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

var scripts = document.getElementsByTagName('script');
var thisScript = null;
var i = scripts.length;
while (i--) {
  if (scripts[i].src && (scripts[i].src.indexOf('yourscript.js') !== -1)) {
    thisScript = scripts[i];
    break;
  }
}
console.log(thisScript);