web-dev-qa-db-fra.com

Comment puis-je référencer la balise de script qui a chargé le script en cours d'exécution?

Comment référencer l'élément de script qui a chargé le javascript en cours d'exécution?

Voici la situation. J'ai un script "maître" chargé haut dans la page, d'abord sous la balise 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" contient un script qui doit pouvoir charger d'autres scripts à la demande. La méthode normale ne fonctionne pas très bien pour moi car je dois ajouter de nouveaux scripts sans faire référence à la balise HEAD, car l'élément HEAD n'a pas terminé le rendu:

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

Ce que je veux faire, c'est faire référence à l'élément de script qui a chargé le script actuel pour pouvoir ensuite ajouter mes nouvelles balises de script chargées dynamiquement dans le DOM après celui-ci.

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

Comment obtenir l'élément de script actuel:

1. Utilisez document.currentScript

document.currentScript renverra l'élément <script> dont le script est en cours de traitement. 

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

Avantages

  • Simple et explicite. Fiable.
  • Pas besoin de modifier la balise de script
  • Fonctionne avec des scripts asynchrones (defer & async)
  • Fonctionne avec des scripts insérés dynamiquement

Problèmes

  • Ne fonctionnera pas dans les anciens navigateurs et IE.

2. Sélectionner le script par identifiant

En attribuant au script un attribut id, vous pourrez facilement le sélectionner par identifiant depuis document.getElementById()

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

Avantages

  • Simple et explicite. Fiable.
  • Presque universellement pris en charge
  • Fonctionne avec des scripts asynchrones (defer & async)
  • Fonctionne avec des scripts insérés dynamiquement

Problèmes

  • Nécessite l'ajout d'un attribut personnalisé à la balise de script
  • L'attribut id peut provoquer un comportement étrange des scripts dans certains navigateurs pour certains cas Edge

3. Sélectionnez le script en utilisant un attribut data-*

Donner au script un attribut data-* vous permettra de le sélectionner facilement de l'intérieur. 

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

Cela présente peu d'avantages par rapport à l'option précédente. 

Avantages

  • Simple et explicite.
  • Fonctionne avec des scripts asynchrones (defer & async)
  • Fonctionne avec des scripts insérés dynamiquement

Problèmes

  • Nécessite l'ajout d'un attribut personnalisé à la balise de script
  • HTML5 et querySelector() non conforme dans tous les navigateurs
  • Moins largement pris en charge que d'utiliser l'attribut id
  • Va circuler <script> avec id cas Edge. 
  • Peut être confus si un autre élément a le même attribut de données et la même valeur sur la page.

4. Sélectionnez le script par src

Au lieu d'utiliser les attributs de données, vous pouvez utiliser le sélecteur pour choisir le script par source:

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

Dans embed.js:

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

Avantages

  • Fiable
  • Fonctionne avec des scripts asynchrones (defer & async)
  • Fonctionne avec des scripts insérés dynamiquement
  • Aucun attribut personnalisé ou id nécessaire

Problèmes

  • Not ne fonctionne-t-il pas avec les scripts locaux?
  • Peut causer des problèmes dans différents environnements, comme le développement et la production
  • Statique et fragile. Changer l'emplacement du fichier de script nécessitera de modifier le script
  • Moins largement pris en charge que d'utiliser l'attribut id
  • Cela posera des problèmes si vous chargez le même script deux fois

5. Boucle sur tous les scripts pour trouver celui que tu veux

Nous pouvons également passer en boucle sur chaque élément de script et vérifier individuellement pour sélectionner celui que nous voulons:

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

Cela nous permet d'utiliser les deux techniques précédentes dans les navigateurs plus anciens qui ne supportent pas bien querySelector() avec des attributs. Par exemple:

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

Cela hérite des avantages et des problèmes de l’approche choisie, mais ne repose pas sur querySelector() et fonctionnera donc avec les anciens navigateurs.

6. Obtenir le dernier script exécuté

Comme les scripts sont exécutés de manière séquentielle, le dernier élément de script sera très souvent le script en cours d'exécution: 

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

Avantages

  • Simple.
  • Presque universellement pris en charge
  • Aucun attribut personnalisé ou id nécessaire

Problèmes

  • Est-ce que not fonctionne avec des scripts asynchrones (defer & async)
  • Not fonctionne-t-il avec des scripts insérés dynamiquement?
549
brice

Étant donné que les scripts sont exécutés de manière séquentielle, la balise de script actuellement exécutée est toujours la dernière balise de script de la page. Donc, pour obtenir la balise script, vous pouvez faire:

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

La chose la plus simple à faire serait probablement de donner à votre balise de script un attribut id.

11
Greg

Les scripts ne sont exécutés de manière séquentielle que s'ils ne possèdent pas d'attribut "différer" ou "asynchrone". Connaître l'un des attributs ID/SRC/TITLE possibles de la balise de script pourrait également fonctionner dans ces cas. Les suggestions de Greg et Justin sont donc correctes.

Il existe déjà une proposition pour un document.currentScript sur les listes du WHATWG.

EDIT: Firefox> 4 implémente déjà cette propriété très utile, mais elle n’est pas disponible dans IE11. J'ai vérifié et uniquement disponible dans Chrome 29 et Safari 8.

EDIT: Personne n’a mentionné la collection "document.scripts", mais j’estime que ce qui suit pourrait être une bonne alternative pour plusieurs navigateurs pour obtenir le script en cours d’exécution:

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

Voici un peu d'un polyfill qui exploite document.CurrentScript s'il existe et revient à trouver le script par ID.

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

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

Si vous incluez cela en haut de chaque balise de script, vous serez sûrement en mesure de savoir systématiquement quelle balise de script est déclenchée et vous pourrez également référencer la balise de script dans le contexte d'un rappel asynchrone.

Non testé, alors laissez des commentaires pour les autres si vous l'essayez.

9
Art Lawry

Il doit fonctionner au chargement de la page et quand une balise de script est ajoutée avec javascript (ex. Avec ajax)

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

Une approche permettant de gérer les scripts asynchrones et différés consiste à utiliser le gestionnaire de chargement onload pour définir un gestionnaire de chargement pour toutes les balises de 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);
});
3
Pete Blois

Suivez ces étapes simples pour obtenir une référence au bloc de script en cours d'exécution:

  1. Mettez une chaîne unique aléatoire dans le bloc de script (doit être unique/différent dans chaque bloc de script)
  2. Itère le résultat de document.getElementsByTagName ('script'), en recherchant la chaîne unique de chaque contenu (obtenue à partir de la propriété innerText/textContent).

Exemple (ABCDE345678 est l'ID unique) :

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

au fait, dans votre cas, vous pouvez simplement utiliser la méthode document.write () à l'ancienne pour inclure un autre script . Comme vous avez mentionné que DOM n'est pas encore restitué, vous pouvez tirer parti du fait que le navigateur exécute toujours le script de manière linéaire sequence (sauf celle différée qui sera rendue plus tard), donc le reste de votre document est toujours "non existant" . Tout ce que vous écrivez via document.write () sera placé juste après le script de l'appelant.

Exemple de page HTML originale :

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

Contenu de script.js :

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

Après rendu, la structure du DOM deviendra:

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY
2
Ferdinand Liu

Pour obtenir le script, celui qui le charge actuellement, vous pouvez utiliser

var thisScript = document.currentScript;

Vous devez conserver une référence au début de votre script pour pouvoir appeler plus tard.

var url = thisScript.src
2

Considérons cet algorithme. Lors du chargement de votre script (s'il existe plusieurs scripts identiques), parcourez document.scripts, recherchez le premier script avec le bon attribut "src", enregistrez-le et marquez-le comme "visité" avec un attribut de données ou un nom de classe unique.

Lors du chargement du script suivant, parcourez à nouveau document.scripts, en transmettant tout script déjà marqué comme visité. Prenez la première instance non consultée de ce script.

Cela suppose que des scripts identiques s'exécutent probablement dans l'ordre dans lequel ils sont chargés, de la tête au corps, de haut en bas, de synchrones à asynchrones.

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

Cela va parcourir tout le script pour le premier script correspondant qui n'est pas marqué avec l'attribut spécial.

Ensuite, marquez ce noeud, s'il est trouvé, avec un attribut de données afin que les analyses ultérieures ne le choisissent pas. Ceci est similaire aux algorithmes BFS et DFS de traversée de graphes, dans lesquels les nœuds peuvent être marqués comme étant "visités" pour empêcher toute nouvelle visite.

2
LSOJ

J'ai trouvé que le code suivant était le plus cohérent, le plus performant et le plus 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);
0
Travis Tidwell

Si vous pouvez assumer le nom de fichier du script, vous pouvez le trouver. Jusqu'à présent, j'ai seulement vraiment testé la fonction suivante dans 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');
0
Justin Love

Il existe un autre moyen simple, si vous connaissez le nom du script (ou au moins une partie de celui-ci):

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

Cela fonctionnera également dans IE11.

0
Fabian von Ellerts