How may I reference the script tag that loaded the currently-executing script?

173,445

Solution 1

How to get the current script element:

1. Use document.currentScript

document.currentScript will return the <script> element whose script is currently being processed.

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

Benefits

  • Simple and explicit. Reliable.
  • Don't need to modify the script tag
  • Works with asynchronous scripts (defer & async)
  • Works with scripts inserted dynamically

Problems

  • Will not work in older browsers and IE.
  • Does not work with modules <script type="module">

2. Select script by id

Giving the script an id attribute will let you easily select it by id from within using document.getElementById().

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

Benefits

  • Simple and explicit. Reliable.
  • Almost universally supported
  • Works with asynchronous scripts (defer & async)
  • Works with scripts inserted dynamically

Problems

  • Requires adding a custom attribute to the script tag
  • id attribute may cause weird behaviour for scripts in some browsers for some edge cases

3. Select the script using a data-* attribute

Giving the script a data-* attribute will let you easily select it from within.

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

This has few benefits over the previous option.

Benefits

  • Simple and explicit.
  • Works with asynchronous scripts (defer & async)
  • Works with scripts inserted dynamically

Problems

  • Requires adding a custom attribute to the script tag
  • HTML5, and querySelector() not compliant in all browsers
  • Less widely supported than using the id attribute
  • Will get around <script> with id edge cases.
  • May get confused if another element has the same data attribute and value on the page.

4. Select the script by src

Instead of using the data attributes, you can use the selector to choose the script by source:

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

In embed.js:

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

Benefits

  • Reliable
  • Works with asynchronous scripts (defer & async)
  • Works with scripts inserted dynamically
  • No custom attributes or id needed

Problems

  • Does not work for local scripts
  • Will cause problems in different environments, like Development and Production
  • Static and fragile. Changing the location of the script file will require modifying the script
  • Less widely supported than using the id attribute
  • Will cause problems if you load the same script twice

5. Loop over all scripts to find the one you want

We can also loop over every script element and check each individually to select the one we want:

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

This lets us use both previous techniques in older browsers that don't support querySelector() well with attributes. For example:

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

This inherits the benefits and problems of whatever approach is taken, but does not rely on querySelector() so will work in older browsers.

6. Get the last executed script

Since the scripts are executed sequentially, the last script element will very often be the currently running script:

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

Benefits

  • Simple.
  • Almost universally supported
  • No custom attributes or id needed

Problems

  • Does not work with asynchronous scripts (defer & async)
  • Does not work with scripts inserted dynamically

Solution 2

Since scripts are executed sequentially, the currently executed script tag is always the last script tag on the page until then. So, to get the script tag, you can do:

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

Solution 3

Probably the easiest thing to do would be to give your scrip tag an id attribute.

Solution 4

Here's a bit of a polyfill that leverages document.CurrentScript if it exists and falls back to finding the script by ID.

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

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

If you include this at the top of every script tag I believe you'll be able to consistently know which script tag is being fired, and you'll also be able to reference the script tag in the context of an asynchronous callback.

Untested, so leave feedback for others if you try it.

Solution 5

Script are executed sequentially only if they do not have either a "defer" or an "async" attribute. Knowing one of the possible ID/SRC/TITLE attributes of the script tag could work also in those cases. So both Greg and Justin suggestions are correct.

There is already a proposal for a document.currentScript on the WHATWG lists.

EDIT: Firefox > 4 already implement this very useful property but it is not available in IE11 last I checked and only available in Chrome 29 and Safari 8.

EDIT: Nobody mentioned the "document.scripts" collection but I believe that the following may be a good cross browser alternative to get the currently running script:

var me = document.scripts[document.scripts.length -1];
Share:
173,445
Admin
Author by

Admin

Updated on September 08, 2020

Comments

  • Admin
    Admin over 3 years

    How can I reference the script element that loaded the javascript that is currently running?

    Here's the situation. I have a "master" script being loaded high in the page, first thing under the HEAD tag.

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

    There is a script in "scripts.js" which needs to be able to do on-demand loading of other scripts. The normal method doesn't quite work for me because I need to add new scripts without referencing the HEAD tag, because the HEAD element hasn't finished rendering:

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

    What I want to do is reference the script element that loaded the current script so that I can then append my new dynamically loaded script tags into the DOM after it.

    <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>
    
  • Jason Thrasher
    Jason Thrasher over 13 years
    This is simple and elegant. There's an example of it in the new Google Charts/Visualizations API if you unpack the javascript. They load JSON data from within the script tag, see: ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js
  • Ken Smith
    Ken Smith over 12 years
    This is a great idea, and it normally works for me. But I should add that there are times when I've found it returning a reference to a different script. Not sure why - haven't been able to track that down. Consequently, I usually go with a different method, e.g., I hard-code the name of the script file, and look for the script tag with that file name.
  • Coffee Bite
    Coffee Bite over 12 years
    One instance that I can think of where this might return incorrect results is when a script tag is added to the DOM asynchronously.
  • King Friday
    King Friday over 11 years
    Yes this can have unpredictable results so you could try using a selector instead: $('script[src*="/mysource.js"]') ???
  • ThemeZ
    ThemeZ about 11 years
    It doesn't work when you have scripts loaded after page loaded. You probably won't get the right tag.
  • Jos de Jong
    Jos de Jong almost 10 years
    This seems to work only for inline scripts, not for external scripts. In the latter case all properties innerText, text, and textContent are empty.
  • Royi Namir
    Royi Namir almost 10 years
    This should be the answer.
  • Hans
    Hans almost 10 years
    Agree with @RoyiNamir. This is the best answer.
  • brice
    brice almost 10 years
    Thanks guys, but you know I answered 4 years after the accepted answer, right :)
  • brice
    brice almost 10 years
    @Josh are you trying it on the console? It's expected to be null in that case. Otherwise, that's a bug against Waterfox. Try this test page: fractallambda.com/misc/testDocumentCurrentScript
  • Nuck
    Nuck over 9 years
    If you're willing to ditch IE support, you can probably express #6 even more succinctly as document.querySelector('script:last-child').remove()
  • Christopher Weiss
    Christopher Weiss over 9 years
    This is a great answer. I would like to point out that according to the HTML5 standard, id is a global attribute and may be specified on all HTML elements, including <script>. w3.org/TR/html5/dom.html#global-attributes
  • ZEE
    ZEE over 9 years
    Great answer... should be answer... and StackOverflow should have a mechanism to mark the best answer... right in top of page (a star flashing with the title), so we can click on it and scrool to the answer that were marked by several users as the best!!!
  • brice
    brice over 9 years
    @ChristopherWeiss I stand corrected! Can't remember where I read that id attributes would be problematic on scripts inside the <head>. Probably a renderer-specific issue, rather than spec issue.
  • neeagl
    neeagl over 9 years
    How to make it work when the script loads in an async way? I am looking to get the GET parameters.
  • jakub.g
    jakub.g almost 9 years
    Note this thing works if you query for self directly in the script main scope. If you do it in a method, other scripts may get loaded in the meantime and distort this.
  • nichochar
    nichochar over 8 years
    Although you are right, there are lot's of cases in which the OP's question are valid, a couple would be: 1) when you're crawling 2) when you are working with the DOM of a client, and he is unwilling to change
  • xwild
    xwild about 8 years
    "document.currentScript" doesn't work for me with dynamic loaded scripts, returns null in the latest chrome/firefox, "last executed script" works ok
  • Supersharp
    Supersharp about 7 years
    doesn't work when script is in a template inserted in a Shadow DOM
  • Moritz
    Moritz almost 7 years
    It's document.scripts not document.script
  • Gary99
    Gary99 almost 7 years
    Welcome to Stack Overflow. Would you care to include some code with the algorithm?
  • LSOJ
    LSOJ almost 7 years
    Thar you go, @Gary99
  • robsch
    robsch over 6 years
    Which option should I use? I'd like to pass some parameters with data-* attributes to the script. Now I'm wondering if this is a good idea. Is there not jQuery option that does the magic?
  • Psyrus
    Psyrus over 6 years
    Full respect to @brice for being humble with his comment about 4 years after accepted answer (I make this comment 9 years after post and have no idea where that accepted answer has gone...). This is a superb answer and helped me considerably. This is the SO community that makes it work so well - producers re-answering old posts with these type of answers benefit consumers like myself who stumble upon these archaic posts and glean valuable nuggets. Thank you kind sir!
  • n.r.
    n.r. over 6 years
    The id attribute is invalid in a script element though. What sorts of problems could this approach generate?
  • Spencer O'Reilly
    Spencer O'Reilly over 6 years
    Since Javascript is often event based then any of the scripts in the array have an equal chance of being the currently executing script, don't they?
  • Travis Tidwell
    Travis Tidwell over 5 years
    I have found that this does not always work. It is better to add a reverse find script instead. 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; } }
  • Fabian von Ellerts
    Fabian von Ellerts over 5 years
    Very outdated. This can be done with the querySelector, a simple oneliner!
  • T.J. Crowder
    T.J. Crowder almost 5 years
    @n.r. - No, all elements can have an id attribute. id, class, and slot are defined at the DOM level, not the HTML level. If you go to the global attributes in HTML and scroll past the list, you'll find "DOM standard defines the user agent requirements for the class, id, and slot attributes for any element in any namespace." followed by "The class, id, and slot attributes may be specified on all HTML elements." The DOM spec covers it here.
  • Luca C.
    Luca C. almost 5 years
    WARNING: this is true only if you don't use asynch or defer
  • den232
    den232 over 4 years
    As of 2019-Oct, document.currentScript still returns null in latest Chrome.
  • brice
    brice over 4 years
    @den232 - Are you trying this in the console? This is expected to return null. Try it by embedding the script on a test page to get the right behaviour in chrome. Try this test page: fractallambda.com/misc/testDocumentCurrentScript
  • den232
    den232 over 4 years
    @brice - Of course. You are sooo right. my duh. Thanks jb
  • Leo
    Leo about 4 years
    document.currentScript returns null in a shadow DOM in Chrome today.'
  • user2880616
    user2880616 about 4 years
    For those using option #2 with jQuery, note that $("#myscript") does not work while the script is executing but you can use $(document.getElementById('myscript'))
  • DrSensor
    DrSensor over 2 years
    If it's type="module", import.meta.url can make "select by src" approach more reliable. However, it still suffer the problem when a file.js src in many <script> tag.