How may I reference the script tag that loaded the currently-executing script?
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>
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>
withid
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];