¿Cómo puedo hacer referencia a la etiqueta de script que cargó el script que se está ejecutando actualmente?


303

¿Cómo puedo hacer referencia al elemento de script que cargó el javascript que se está ejecutando actualmente?

Aquí está la situación. Tengo un script "maestro" cargado en la parte superior de la página, lo primero bajo la etiqueta 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>

Hay un script en "scripts.js" que necesita poder cargar otros scripts a pedido. El método normal no funciona para mí porque necesito agregar nuevos scripts sin hacer referencia a la etiqueta HEAD, porque el elemento HEAD no ha terminado de renderizarse:

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

Lo que quiero hacer es hacer referencia al elemento de script que cargó el script actual para que luego pueda agregar mis nuevas etiquetas de script cargadas dinámicamente en el DOM después de él.

<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
Una advertencia: modificar el DOM mientras aún se está cargando le causará mucho daño en IE6 e IE7 . Será mejor que ejecutes ese código después de cargar la página.
Tríptico

66
Parece que ahora está en caniuse: caniuse.com/#feat=document-currentscript
Tyler el

Respuestas:


653

Cómo obtener el elemento de script actual:

1. Uso document.currentScript

document.currentScriptdevolverá el <script>elemento cuyo script se está procesando actualmente.

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

Beneficios

  • Simple y explícito. De confianza.
  • No es necesario modificar la etiqueta del script
  • Funciona con scripts asincrónicos ( defer& async)
  • Funciona con scripts insertados dinámicamente.

Problemas

  • No funcionará en navegadores antiguos e IE.
  • No funciona con módulos. <script type="module">

2. Seleccione script por id

Darle al script un atributo de id le permitirá seleccionarlo fácilmente por id desde dentro usando document.getElementById().

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

Beneficios

  • Simple y explícito. De confianza.
  • Casi universalmente compatible
  • Funciona con scripts asincrónicos ( defer& async)
  • Funciona con scripts insertados dinámicamente.

Problemas

  • Requiere agregar un atributo personalizado a la etiqueta del script
  • id El atributo puede causar un comportamiento extraño para los scripts en algunos navegadores para algunos casos extremos

3. Seleccione el script usando un data-*atributo

Darle un data-*atributo al script le permitirá seleccionarlo fácilmente desde adentro.

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

Esto tiene pocos beneficios sobre la opción anterior.

Beneficios

  • Simple y explícito.
  • Funciona con scripts asincrónicos ( defer& async)
  • Funciona con scripts insertados dinámicamente.

Problemas

  • Requiere agregar un atributo personalizado a la etiqueta del script
  • HTML5, y querySelector()no es compatible con todos los navegadores
  • Menos compatible que usar el idatributo
  • Se moverá <script>con idcajas de borde.
  • Puede confundirse si otro elemento tiene el mismo atributo y valor de datos en la página.

4. Seleccione el script por src

En lugar de usar los atributos de datos, puede usar el selector para elegir el script por fuente:

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

En embed.js:

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

Beneficios

  • De confianza
  • Funciona con scripts asincrónicos ( defer& async)
  • Funciona con scripts insertados dinámicamente.
  • No se necesitan atributos personalizados o identificación

Problemas

  • No no trabajar para los scripts locales
  • Causará problemas en diferentes entornos, como Desarrollo y Producción
  • Estática y frágil. Cambiar la ubicación del archivo de script requerirá modificar el script
  • Menos compatible que usar el idatributo
  • Causará problemas si carga el mismo script dos veces

5. Recorre todas las secuencias de comandos para encontrar la que deseas

También podemos recorrer cada elemento del script y verificar cada uno individualmente para seleccionar el que queremos:

<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>

Esto nos permite usar ambas técnicas anteriores en navegadores antiguos que no son compatibles querySelector()con los atributos. Por ejemplo:

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

Esto hereda los beneficios y problemas de cualquier enfoque que se adopte, pero no depende de querySelector()eso, por lo que funcionará en navegadores más antiguos.

6. Obtenga el último script ejecutado

Dado que las secuencias de comandos se ejecutan secuencialmente, el último elemento de secuencia de comandos con frecuencia será la secuencia de comandos que se está ejecutando actualmente:

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

Beneficios

  • Sencillo.
  • Casi universalmente compatible
  • No se necesitan atributos personalizados o identificación

Problemas

  • No no trabajar con secuencias de comandos asíncronos ( deferY async)
  • No no trabajar con guiones dinámicamente insertadas

44
Esta debería ser la respuesta.
Royi Namir

1
De acuerdo con @RoyiNamir. Esta es la mejor respuesta.
Hans

27
Gracias chicos, pero saben que respondí 4 años después de la respuesta aceptada, cierto :)
brice

55
"document.currentScript" no funciona para mí con scripts dinámicos cargados, devuelve nulo en el último chrome / firefox, "último script ejecutado" funciona bien
xwild

1
no funciona cuando scriptse templateinserta en un DOM de sombra
Supersharp

86

Dado que los scripts se ejecutan secuencialmente, la etiqueta de script ejecutada actualmente es siempre la última etiqueta de script en la página hasta ese momento. Entonces, para obtener la etiqueta del script, puede hacer:

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

3
Esto es simple y elegante. Hay un ejemplo de ello en la nueva API de gráficos / visualizaciones de Google si desempaqueta el javascript. Cargan datos JSON desde la etiqueta del script, consulte: ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js
Jason Thrasher

1
Esta es una gran idea, y normalmente funciona para mí. Pero debo agregar que hay momentos en que he encontrado que devuelve una referencia a un script diferente. No estoy seguro de por qué, no he podido rastrear eso. En consecuencia, generalmente uso un método diferente, por ejemplo, codifico el nombre del archivo de script y busco la etiqueta del script con ese nombre de archivo.
Ken Smith

53
Una instancia en la que puedo pensar donde esto podría devolver resultados incorrectos es cuando se agrega una etiqueta de script al DOM de forma asincrónica.
Bocado de café

99
Sí, esto puede tener resultados impredecibles, por lo que podría intentar usar un selector: $ ('script [src * = "/ mysource.js"]') ???
Jason Sebring

77
No funciona cuando tiene scripts cargados después de cargar la página. Probablemente no obtendrá la etiqueta correcta.
ThemeZ

11

Probablemente lo más fácil sería darle a su etiqueta de scrip un id atributo .


2
Aunque tiene razón, hay muchos casos en los que la pregunta del OP es válida, un par sería: 1) cuando está rastreando 2) cuando está trabajando con el DOM de un cliente y él no está dispuesto a cambiar
nichochar

10

Las secuencias de comandos se ejecutan secuencialmente solo si no tienen un atributo "diferido" o "asíncrono". Conocer uno de los posibles atributos ID / SRC / TITLE de la etiqueta del script también podría funcionar en esos casos. Entonces, las sugerencias de Greg y Justin son correctas.

Ya hay una propuesta para un document.currentScripten las listas de WHATWG.

EDITAR : Firefox> 4 ya implementa esta propiedad muy útil, pero no está disponible en IE11 la última vez que revisé y solo está disponible en Chrome 29 y Safari 8.

EDITAR : Nadie mencionó la colección "document.scripts", pero creo que lo siguiente puede ser una buena alternativa entre navegadores para obtener el script actualmente en ejecución:

var me = document.scripts[document.scripts.length -1];

1
Es document.scripts no document.script
Moritz

9

Aquí hay un poco de un polyfill que aprovecha document.CurrentScriptsi existe y cae de nuevo a la búsqueda de la secuencia de comandos por ID.

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

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

Si incluye esto en la parte superior de cada etiqueta de script, creo que podrá saber constantemente qué etiqueta de script se está activando, y también podrá hacer referencia a la etiqueta de script en el contexto de una devolución de llamada asincrónica.

Sin probar, así que deja comentarios para otros si lo intentas.


Sin embargo, el idatributo no es válido en un scriptelemento. ¿Qué tipo de problemas podría generar este enfoque?
nr.

1
@nr: no, todos los elementos pueden tener un idatributo. id, classy slotse definen en el nivel DOM, no en el nivel HTML. Si va a los atributos globales en HTML y se desplaza más allá de la lista, encontrará que "el estándar DOM define los requisitos de agente de usuario para los atributos de clase, id y slot para cualquier elemento en cualquier espacio de nombres". seguido de "Los atributos de clase, id y slot pueden especificarse en todos los elementos HTML". La especificación DOM lo cubre aquí .
TJ Crowder

6

Debe funcionar al cargar la página y cuando se agrega una etiqueta de script con javascript (por ejemplo, con ajax)

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

3

Siga estos sencillos pasos para obtener referencias al bloque de script actual en ejecución:

  1. Ponga una cadena única aleatoria dentro del bloque de secuencia de comandos (debe ser única / diferente en cada bloque de secuencia de comandos)
  2. Iterar el resultado de document.getElementsByTagName ('script'), buscando la cadena única de cada uno de su contenido (obtenido de la propiedad innerText / textContent).

Ejemplo (ABCDE345678 es la ID única) :

<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>

por cierto, para su caso, simplemente puede usar el método antiguo de document.write () para incluir otro script. Como mencionó que DOM aún no se procesa, puede aprovechar el hecho de que el navegador siempre ejecuta el script en secuencia lineal (excepto el diferido que se procesará más adelante), por lo que el resto de su documento aún "no existe". Todo lo que escriba a través de document.write () se colocará justo después del script de llamada.

Ejemplo de página HTML original :

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

Contenido de script.js :

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

Después de renderizado, la estructura DOM se convertirá en:

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

Esto parece funcionar solo para scripts en línea, no para scripts externos. En el último caso, todas las propiedades innerText, text y textContent están vacías.
Jos de Jong

3

Un enfoque para tratar con scripts asíncronos y diferidos es aprovechar el controlador de carga: establecer un controlador de carga para todas las etiquetas de script y el primero que se ejecute debe ser suyo.

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);
});

3

Para obtener el script, que actualmente cargó el script, puede usar

var thisScript = document.currentScript;

Debe mantener una referencia al comienzo de su secuencia de comandos, para poder llamar más tarde

var url = thisScript.src

2

Considera este algoritmo. Cuando se carga el script (si hay varios scripts idénticos), revise document.scripts, busque el primer script con el atributo "src" correcto, guárdelo y márquelo como 'visitado' con un atributo de datos o className único.

Cuando se carga el siguiente script, escanee nuevamente document.scripts, pasando sobre cualquier script ya marcado como visitado. Tome la primera instancia no visitada de ese script.

Esto supone que scripts idénticos probablemente se ejecutarán en el orden en que se cargan, de la cabeza al cuerpo, de arriba a abajo, de síncrono a asíncrono.

(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;
  }
})();

Esto buscará en todo el script el primer script coincidente que no esté marcado con el atributo especial.

Luego marque ese nodo, si lo encuentra, con un atributo de datos para que los escaneos posteriores no lo elijan. Esto es similar a los algoritmos transversales BFS y DFS del gráfico donde los nodos pueden marcarse como 'visitados' para evitar la revisión.


Bienvenido a Stack Overflow. ¿Te gustaría incluir algún código con el algoritmo?
Gary99

Thar you go, @ Gary99
LSOJ

0

Tengo esto, que funciona en FF3, IE6 y 7. Los métodos en los scripts cargados a pedido no están disponibles hasta que se completa la carga de la página, pero esto sigue siendo muy útil.

//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 );
}

0

Si puede asumir el nombre del archivo del script, puede encontrarlo. Hasta ahora solo he probado la siguiente función en 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');

1
Muy anticuado ¡Esto se puede hacer con querySelector, un simple oneliner!
Fabian von Ellerts

-1

He encontrado que el siguiente código es el más consistente, eficiente y simple.

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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.