Come posso fare riferimento al tag dello script che ha caricato lo script attualmente in esecuzione?


303

Come posso fare riferimento all'elemento script che ha caricato il javascript attualmente in esecuzione?

Ecco la situazione. Ho uno script "master" che viene caricato in alto nella pagina, prima cosa sotto il tag 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>

C'è uno script in "scripts.js" che deve essere in grado di eseguire il caricamento su richiesta di altri script. Il metodo normale non funziona abbastanza per me perché devo aggiungere nuovi script senza fare riferimento al tag HEAD, perché l'elemento HEAD non ha terminato il rendering:

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

Quello che voglio fare è fare riferimento all'elemento dello script che ha caricato lo script corrente in modo da poter aggiungere i miei nuovi tag di script caricati dinamicamente nel DOM dopo di esso.

<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
Un avvertimento: la modifica del DOM mentre è ancora in fase di caricamento causerà un mondo di dolore in IE6 e IE7 . Farai meglio a eseguire quel codice dopo il caricamento della pagina.
Trittico

6
Sembra che sia ora su caniuse: caniuse.com/#feat=document-currentscript
Tyler,

Risposte:


653

Come ottenere l'elemento di script corrente:

1. Usa document.currentScript

document.currentScriptrestituirà l' <script>elemento il cui script è attualmente in fase di elaborazione.

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

Benefici

  • Semplice ed esplicito. Affidabile.
  • Non è necessario modificare il tag dello script
  • Funziona con script asincroni ( defer& async)
  • Funziona con script inseriti in modo dinamico

I problemi

  • Non funzionerà nei browser e IE precedenti.
  • Non funziona con i moduli <script type="module">

2. Seleziona lo script per ID

Dare allo script un attributo id ti permetterà di selezionarlo facilmente per id dall'interno document.getElementById().

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

Benefici

  • Semplice ed esplicito. Affidabile.
  • Quasi universalmente supportato
  • Funziona con script asincroni ( defer& async)
  • Funziona con script inseriti in modo dinamico

I problemi

  • Richiede l'aggiunta di un attributo personalizzato al tag dello script
  • id l'attributo può causare comportamenti strani per gli script in alcuni browser per alcuni casi limite

3. Selezionare lo script utilizzando un data-*attributo

Dare allo script un data-*attributo ti permetterà di selezionarlo facilmente dall'interno.

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

Ciò ha pochi vantaggi rispetto all'opzione precedente.

Benefici

  • Semplice ed esplicito.
  • Funziona con script asincroni ( defer& async)
  • Funziona con script inseriti in modo dinamico

I problemi

  • Richiede l'aggiunta di un attributo personalizzato al tag dello script
  • HTML5 e querySelector()non conforme in tutti i browser
  • Meno ampiamente supportato rispetto all'uso iddell'attributo
  • Andrà in giro <script>con idcasi limite.
  • Potrebbe essere confuso se un altro elemento ha lo stesso attributo e valore di dati sulla pagina.

4. Seleziona lo script per src

Invece di usare gli attributi dei dati, puoi usare il selettore per scegliere lo script per fonte:

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

In embed.js:

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

Benefici

  • Affidabile
  • Funziona con script asincroni ( defer& async)
  • Funziona con script inseriti in modo dinamico
  • Non sono necessari attributi o ID personalizzati

I problemi

  • Does non lavorare per gli script locali
  • Causerà problemi in diversi ambienti, come sviluppo e produzione
  • Statico e fragile. La modifica del percorso del file di script richiederà la modifica dello script
  • Meno ampiamente supportato rispetto all'uso iddell'attributo
  • Causerà problemi se carichi lo stesso script due volte

5. Scorri tutti gli script per trovare quello che desideri

Possiamo anche passare in rassegna ogni elemento dello script e controllarli singolarmente per selezionare quello che vogliamo:

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

Questo ci consente di utilizzare entrambe le tecniche precedenti nei browser meno recenti che non supportano querySelector()bene gli attributi. Per esempio:

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

Ciò eredita i vantaggi e i problemi di qualsiasi approccio venga adottato, ma non si basa su di esso, querySelector()quindi funzionerà nei browser più vecchi.

6. Ottieni l'ultimo script eseguito

Poiché gli script vengono eseguiti in sequenza, l'ultimo elemento dello script sarà molto spesso lo script attualmente in esecuzione:

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

Benefici

  • Semplice.
  • Quasi universalmente supportato
  • Non sono necessari attributi o ID personalizzati

I problemi

  • Non non lavorare con gli script asincroni ( defer& async)
  • Non non lavorare con gli script inseriti in modo dinamico

4
Questa dovrebbe essere la risposta.
Royi Namir,

1
Concordo con @RoyiNamir. Questa è la risposta migliore
Hans,

27
Grazie ragazzi, ma sapete che ho risposto 4 anni dopo la risposta accettata, giusto :)
brice

5
"document.currentScript" non funziona per me con script caricati dinamici, restituisce null nell'ultimo chrome / firefox, "ultimo script eseguito" funziona bene
xwild

1
non funziona quando scriptè templateinserito in un Shadow DOM
Supersharp

86

Poiché gli script vengono eseguiti in sequenza, il tag di script attualmente eseguito è sempre l'ultimo tag di script sulla pagina fino ad allora. Quindi, per ottenere il tag script, puoi fare:

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

3
Questo è semplice ed elegante. Ne esiste un esempio nella nuova API Google Charts / Visualizations se decomprimi javascript. Caricano i dati JSON dall'interno del tag dello script, consultare: ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js
Jason Thrasher,

1
Questa è un'ottima idea e normalmente funziona per me. Ma dovrei aggiungere che ci sono volte in cui l'ho trovato restituendo un riferimento a uno script diverso. Non so perché - non sono riuscito a rintracciarlo. Di conseguenza, di solito vado con un metodo diverso, ad esempio codifico il nome del file di script e cerco il tag dello script con quel nome di file.
Ken Smith,

53
Un'istanza che mi viene in mente dove ciò potrebbe restituire risultati errati è quando un tag di script viene aggiunto al DOM in modo asincrono.
Coffee Bite,

9
Sì, questo può avere risultati imprevedibili, quindi puoi provare a usare un selettore: $ ('script [src * = "/ mysource.js"]') ???
Jason Sebring,

7
Non funziona quando hai gli script caricati dopo il caricamento della pagina. Probabilmente non otterrai il tag giusto.
ThemeZ

11

Probabilmente la cosa più semplice da fare sarebbe dare un idattributo al tuo tag script .


2
Sebbene tu abbia ragione, ci sono molti casi in cui la domanda del PO è valida, una coppia sarebbe: 1) quando stai strisciando 2) quando stai lavorando con il DOM di un cliente, e lui non è disposto a cambiare
nichochar,

10

Gli script vengono eseguiti in sequenza solo se non dispongono dell'attributo "differisci" o "asincrono". Conoscere uno dei possibili attributi ID / SRC / TITLE del tag script potrebbe funzionare anche in questi casi. Quindi entrambi i suggerimenti di Greg e Justin sono corretti.

Esiste già una proposta per un document.currentScriptelenco WHATWG.

EDIT : Firefox> 4 implementa già questa proprietà molto utile ma non è disponibile in IE11 e ho controllato l'ultima volta e disponibile solo in Chrome 29 e Safari 8.

EDIT : Nessuno ha menzionato la raccolta "document.scripts", ma credo che quanto segue possa essere una buona alternativa cross-browser per ottenere lo script attualmente in esecuzione:

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

1
È document.scripts non document.script
Moritz

9

Ecco un po 'di polyfill che sfrutta document.CurrentScriptse esiste e ricade nella ricerca dello script per ID.

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

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

Se lo includi nella parte superiore di ogni tag di script, credo che sarai in grado di sapere costantemente quale tag di script viene attivato e sarai anche in grado di fare riferimento al tag di script nel contesto di un callback asincrono.

Non testato, quindi lascia un feedback per gli altri se lo provi.


L' idattributo non è valido in un scriptelemento però. Quali tipi di problemi potrebbe generare questo approccio?
n.

1
@nr - No, tutti gli elementi possono avere un idattributo. id, classe slotsono definiti a livello di DOM, non a livello di HTML. Se vai agli attributi globali in HTML e scorri l'elenco, troverai "Lo standard DOM definisce i requisiti dell'agente utente per gli attributi class, id e slot per qualsiasi elemento in qualsiasi spazio dei nomi". seguito da "Gli attributi class, id e slot possono essere specificati su tutti gli elementi HTML." Le specifiche DOM lo coprono qui .
TJ Crowder,

6

Deve funzionare al caricamento della pagina e quando un tag di script viene aggiunto con javascript (es. Con ajax)

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

3

Seguire questi semplici passaggi per ottenere riferimento all'attuale blocco di script in esecuzione:

  1. Inserisci una stringa univoca casuale all'interno del blocco di script (deve essere univoco / diverso in ciascun blocco di script)
  2. Risultato iterato di document.getElementsByTagName ('script'), cercando la stringa univoca da ciascuno dei loro contenuti (ottenuto dalla proprietà innerText / textContent).

Esempio (ABCDE345678 è l'ID univoco) :

<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, nel tuo caso, puoi semplicemente usare il vecchio metodo document.write () per includere un altro script. Come hai detto che il DOM non è ancora reso, puoi trarre vantaggio dal fatto che il browser esegue sempre lo script in sequenza lineare (ad eccezione di quello differito che verrà reso in seguito), quindi il resto del tuo documento non è ancora "non esiste". Tutto ciò che scrivi attraverso document.write () verrà posizionato subito dopo lo script del chiamante.

Esempio di pagina HTML originale :

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

Contenuto di script.js :

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

Dopo il rendering, la struttura DOM diventerà:

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

Questo sembra funzionare solo per gli script incorporati, non per gli script esterni. In quest'ultimo caso tutte le proprietà innerText, text e textContent sono vuote.
Jos de Jong,

3

Un approccio per gestire gli script asincroni e differiti consiste nell'utilizzare il gestore onload, impostare un gestore onload per tutti i tag di script e il primo che viene eseguito dovrebbe essere tuo.

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

Per ottenere lo script, quello attualmente caricato lo script è possibile utilizzare

var thisScript = document.currentScript;

Devi mantenere un riferimento all'inizio del tuo script, in modo da poter chiamare in seguito

var url = thisScript.src

2

Considera questo algoritmo. Quando lo script viene caricato (se sono presenti più script identici), cercare document.scripts, trovare il primo script con l'attributo "src" corretto e salvarlo e contrassegnarlo come "visitato" con un attributo di dati o un nome di classe univoco.

Quando viene caricato lo script successivo, esegui nuovamente la scansione di document.scripts, passando su qualsiasi script già contrassegnato come visitato. Prendi la prima istanza non visitata di quello script.

Ciò presuppone che gli script identici verranno probabilmente eseguiti nell'ordine in cui vengono caricati, dalla testa al corpo, dall'alto verso il basso, da sincrono ad asincrono.

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

Questo eseguirà la scansione di tutto lo script per il primo script corrispondente che non è contrassegnato con l'attributo speciale.

Quindi contrassegnare quel nodo, se trovato, con un attributo di dati in modo che le scansioni successive non lo scelgano. Questo è simile agli algoritmi BFS e DFS di attraversamento di grafici in cui i nodi possono essere contrassegnati come "visitati" per impedire la rivisitazione.


Benvenuto in Stack Overflow. Ti andrebbe di includere del codice con l'algoritmo?
Gary99,

Thar you go, @ Gary99
LSOJ

0

Ho questo, che funziona in FF3, IE6 e 7. I metodi negli script caricati su richiesta non sono disponibili fino al completamento del caricamento della pagina, ma questo è ancora molto utile.

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

Se puoi assumere il nome del file dello script, puoi trovarlo. Finora ho testato solo le seguenti funzioni in 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
Molto obsoleto Questo può essere fatto con querySelector, un semplice oneliner!
Fabian von Ellerts il

-1

Ho trovato il seguente codice come il più coerente, performante e semplice.

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.