JavaScript: ¿cómo obtengo la URL del script que se está llamando?

81

Incluyo myscript.js en el archivo http://site1.com/index.htmlcomo este:

<script src=http://site2.com/myscript.js></script>

Dentro de "myscript.js", quiero obtener acceso a la URL " http://site2.com/myscript.js ". Me gustaría tener algo como esto:

function getScriptURL() {
    // something here
    return s
}

alert(getScriptURL());

Lo que alertaría " http://site2.com/myscript.js " si se llama desde el index.html mencionado anteriormente.

MikeC8
fuente
posible duplicado de ¿Cuál es la URL de mi script src?
ripper234
Según sus URL de ejemplo, es posible que desee observar qué comportamiento espera si el navegador está configurado para bloquear scripts de terceros.

Respuestas:

58

De http://feather.elektrum.org/book/src.html :

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

La variable myScriptahora tiene el elemento dom del script. Puede obtener la URL src usando myScript.src.

Tenga en cuenta que esto debe ejecutarse como parte de la evaluación inicial del script. Si desea no contaminar el espacio de nombres de Javascript, puede hacer algo como:

var getScriptURL = (function() {
    var scripts = document.getElementsByTagName('script');
    var index = scripts.length - 1;
    var myScript = scripts[index];
    return function() { return myScript.src; };
})();
lambacck
fuente
23
¿Sin embargo, esto siempre devolverá la URL del script correcto en todos los navegadores? Parece que devolverá la última etiqueta de secuencia de comandos, pero ¿qué pasa si el documento tiene más de una etiqueta de secuencia de comandos?
MikeC8
3
Ok ... mi pregunta es, ¿todos los navegadores siempre cargan y ejecutan completamente el contenido completo de un script remoto antes de pasar a la siguiente etiqueta de script? ¿Cuán rigurosamente está estandarizado? Podría imaginarlo sucediendo en paralelo ...
MikeC8
1
Se requiere que los scripts se ejecuten completamente y en orden debido a lo que sucedería si la etiqueta del script contuviera un document.write. Este es el motivo de las recomendaciones de colocar scripts en la parte inferior de la página porque en realidad bloquearán la carga de otros contenidos. Dicho esto, HTML5 modifica eso con el uso de los atributos async y defer: whatwg.org/specs/web-apps/current-work/multipage/…
lambacck
9
Esto no funciona si carga el script después de que la página se haya cargado usando algo como esto: document.getElementsByTagName("head")[0].appendChild(scriptElement);
Seanonymous
16
Me he encontrado con un caso en el que este algoritmo no funciona de manera confiable. Otras etiquetas de secuencia de comandos que están configuradas como asíncronas pueden ejecutarse entre la solicitud y la ejecución de la secuencia de comandos. Estos scripts pueden agregar otros scripts al DOM que aparecen después del suyo. Cuando su script se ejecuta, el último script de la página ya no es suyo y srcse devuelve el error .
Karl
54

Puede agregar el atributo id a su etiqueta de secuencia de comandos (incluso si está dentro de una etiqueta de cabeza):

<script id="myscripttag" src="http://site2.com/myscript.js"></script>

y luego acceda a su src de la siguiente manera:

document.getElementById("myscripttag").src

por supuesto, el valor de id debería ser el mismo para todos los documentos que incluyan su script, pero no creo que sea un gran inconveniente para usted.

tsds
fuente
1
Esta respuesta debe marcarse como "aceptada", ya que cubre los casos en los que llama al método que no está en el contexto del script "global" o en el script "async", y no depende de la implementación del navegador.
Sergei Kovalenko
Tenga en cuenta que .src puede devolver una ruta absoluta, incluso si se especificó una ruta relativa. Puede usar.getAttribute('src')
Илья Зеленько
18

Escribí una clase para encontrar la ruta de los scripts que funciona con la carga retrasada y las etiquetas de scripts asíncronos.

Tenía algunos archivos de plantilla que eran relativos a mis scripts, así que en lugar de codificarlos, creé la clase para crear las rutas automáticamente. La fuente completa está aquí en github.

Hace un tiempo usé argumentos.callee para intentar hacer algo similar, pero recientemente leí en el MDN que no está permitido en modo estricto .

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}
QueueHammer
fuente
1
Un poco tarde para la fiesta aquí, pero estaba probando este fragmento de código y encontré que la parte donde agrega 2 al índice actual en el bucle for "callerIndex = Number (i) + 2;" parece que romperse es innecesario y hace que no funcione. Simplemente eliminando el "+ 2" lo hace funcionar. ¿Hay algo que estoy malinterpretando o algún otro escenario para el que sería necesario ese + 2?
Scott Smith
2
no necesitas lanzar "Error" de esta manera (para obtener su ".stack") es solo un objeto como otros: console.log (new Error (). stack);
Abdullah
1
Gracias por esta idea y gracias a @ AbdullahAydın por la idea de prevenir un lanzamiento. Entonces supongo que el siguiente one-liner haría el truco, ¿no? var scriptUrl = new Error (). stack.match (/ @ (https?: \ / \ /.+): \ d +: \ d + /) [1]
Pierre-Antoine
1
También @ Pierre-Antoine tenga en cuenta que la propiedad Error.prototype.stack no es estándar: / debe usarla con cuidado. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Abdullah
3
@ AbdullahAydın: Tenga en cuenta que la propiedad de pila de un nuevo error no se completa en los navegadores IE y Edge hasta que se lanza el error.
Bob Arlof
15

si tiene la oportunidad de usar jQuery, el código se vería así:

$('script[src$="/myscript.js"]').attr('src');
Sr. Calabaza
fuente
¿Funciona con scripts de carga diferida, asíncrona y diferida?
Stephan
Solo busca en el DOM una etiqueta de secuencia de comandos con el src "/myscript.js". otros atributos no importarán
Rebs
Para usar esto con wordpress to en cualquier otro lugar que agregue la versión, debe usar $ ('script [src * = "/ myscript.js"]'). Attr ('src'); de esta manera ignorará el? ver = 2.3.3 al final del script. El * lo mantendrá funcionando independientemente de lo que esté al final.
Mav2287
15

Solución simple y sencilla que funciona muy bien:

Si no es IE, puede usar document.currentScript
Para IE, puede hacerlo document.querySelector('script[src*="myscript.js"]')
:

function getScriptURL(){
 var script =  document.currentScript || document.querySelector('script[src*="myscript.js"]')
 return script.src
}
pery mimon
fuente
2

El siguiente código le permite encontrar el elemento de script con el nombre de pila

var scripts = document.getElementsByTagName( 'script' );
        var len = scripts.length
        for(var i =0; i < len; i++) {
            if(scripts[i].src.search("<your JS file name") > 0 && scripts[i].src.lastIndexOf("/") >= 0) {
                absoluteAddr = scripts[i].src.substring(0, scripts[i].src.lastIndexOf("/") + 1);
                break;
            }
        }
Varun Bhatia
fuente
-6

¿No puede usar location.href o location.host y luego agregar el nombre del script?

Pablo
fuente
1
Eso no funcionará, porque el script se ejecuta dentro de la página site1.com/index.html . Por lo tanto, incluso si el script se carga desde site2.com, si accede a la ubicación desde el script, devolverá " site1.com/index.html " ...
MikeC8