Dynamically Importing JavaScript
Asked Answered
A

3

4

What is the correct way to dynamically import JavaScript (.js) files into a parent JavaScript code, please?

I am using the following code, but it seems not correct:

    function loadjscssfile(filename, filetype)
{
    //if filename is a external JavaScript file
    if (filetype=="js")
    {
        var fileref=document.createElement('script');
        fileref.setAttribute("type","text/javascript");
        fileref.setAttribute("src", filename);
    }
    //if filename is an external CSS file
    else if (filetype=="css")
    {
        var fileref=document.createElement("link");
        fileref.setAttribute("rel", "stylesheet");
        fileref.setAttribute("type", "text/css");
        fileref.setAttribute("href", filename);
    }
    if (typeof fileref!="undefined")
    document.getElementsByTagName("head")[0].appendChild(fileref)
}

I think, the code is not correct, because, in the master JavaScript code, I can no read variables defined in the imported code, such as:

var fileRef = loadjscssfile('Language/svk.js', 'js');
alert("Pet Name: " + PETNAME);

imported svk.js file contains the only code:

// JavaScript Document
var PETNAME = "Beauty";

Thank you.

Arrival answered 2/6, 2012 at 18:4 Comment(6)
Check whether importing js file is suceeds or not. Den try to access the variables defined in loaded js.Incrustation
@Sarfraz: Hi, yes, tye code gets imported, I can confirm it so, that I put the alert("Pet Name: " + PETNAME); into the imported code, and there it gets run, and I see the alert box with appropriate value. However, if the alert("Pet Name: " + PETNAME); is moved to the master file, I can not get the value of PETNAMEArrival
You have to remember that it takes some time for the file to load and be parsed, you can't access its content right after you call you function. Perhaps in your imported file you can add a function call to a callback in the original code in order to signal that the imported file was successfully loaded.Sternick
take a look at this: #950587 there is a good answer and a good jQuery example of using variables after the script has been read/loadedKerbstone
@Yaniro: Hi, thank you for your response. How do I know, that the code has been imported? Should that simply be the last line in my imported code? Would you have an example for me, please? Thank you for this good tip, I have some ideas to further explore.Arrival
@Bunkai.Satori: checkout my answer at the end.Sternick
M
2

The reason you can't read the PETNAME variable is that dynamically injecting scripts like this is asynchronous and non-blocking. This means that your alert executes before the script has actually been loaded. Instead, you might have to poll for the existence of the PETNAME variable:

var waitForPETNAME = function(){
        if (typeof PETNAME === 'undefined') {
            setTimeout(waitForPETNAME, 15);
        } else {
            // execute code that uses PETNAME
        }
    };

waitForPETNAME();

Also, a more fool-proof way to inject elements dynamically is to insert them before the first script element since you know for sure that a script element has to exist (otherwise you wouldn't be executing code). In other words, replace:

document.getElementsByTagName("head")[0].appendChild(fileref)

with:

var insref = document.getElementsByTagName('script')[0];
insref.parentNode.insertBefore(fileref, insref);
Madeleinemadelena answered 2/6, 2012 at 18:12 Comment(3)
+1 and thank you for your answer and additional ideas for improvement. Regarding setTimeout(waitForPETNAME, 15); I would have one question, please: ist the code stopped during waiting for another function call? Or, does the code continue running, and the funciton is called assynchronously? Regarding your suggested improvement, can I ask, please, in which areas can my code fail? I simply did not get, in what areas is your code stronger. Sorry for overlooking that.Arrival
The code continues running and the timeout poll is called asynchronously. As for the improvement, HTML5 no longer requires a <head> tag, or in some older browsers you may not be able to append there when the script executes. The improvement I suggested avoids these two situations.Madeleinemadelena
All the answers on my question were valid, and thank you all for responding. I granted +1 for every good answer. However, I have to chose only one answer as the Accepted Answer and because mVChr provided valuable improvements of my code, I would like to mark this answer as the Accepted Answer. Thank you all.Arrival
P
4

You can't use variables and functions defined in the external JS file immediatly after inserting the <script> tag. It takes the browser a few milliseconds to load the file and execute it.

You would have to work with some kind of callback in order to have the proper loading order for your JavaScript.

For proper conditional loading of JavaScript have a look at Require.js. There the Asynchronous Module Definition pattern is implemented.

Polygon answered 2/6, 2012 at 18:11 Comment(1)
+1 - Hi Sirko. Thank you for your answer. Yes, apparently, my question is nothing new, as more people immediately knew the origin of my problem. I will take a look at Require.js.Arrival
S
3

In svk.js add the following (after the variable deceleration):

svkLoaded();

In the master code file add the following:

function svkLoaded()
{
    alert("Pet Name: " + PETNAME);
}
Sternick answered 2/6, 2012 at 18:19 Comment(1)
+1 - Excellent advice and explanation. Thank you very much Yaniro.Arrival
M
2

The reason you can't read the PETNAME variable is that dynamically injecting scripts like this is asynchronous and non-blocking. This means that your alert executes before the script has actually been loaded. Instead, you might have to poll for the existence of the PETNAME variable:

var waitForPETNAME = function(){
        if (typeof PETNAME === 'undefined') {
            setTimeout(waitForPETNAME, 15);
        } else {
            // execute code that uses PETNAME
        }
    };

waitForPETNAME();

Also, a more fool-proof way to inject elements dynamically is to insert them before the first script element since you know for sure that a script element has to exist (otherwise you wouldn't be executing code). In other words, replace:

document.getElementsByTagName("head")[0].appendChild(fileref)

with:

var insref = document.getElementsByTagName('script')[0];
insref.parentNode.insertBefore(fileref, insref);
Madeleinemadelena answered 2/6, 2012 at 18:12 Comment(3)
+1 and thank you for your answer and additional ideas for improvement. Regarding setTimeout(waitForPETNAME, 15); I would have one question, please: ist the code stopped during waiting for another function call? Or, does the code continue running, and the funciton is called assynchronously? Regarding your suggested improvement, can I ask, please, in which areas can my code fail? I simply did not get, in what areas is your code stronger. Sorry for overlooking that.Arrival
The code continues running and the timeout poll is called asynchronously. As for the improvement, HTML5 no longer requires a <head> tag, or in some older browsers you may not be able to append there when the script executes. The improvement I suggested avoids these two situations.Madeleinemadelena
All the answers on my question were valid, and thank you all for responding. I granted +1 for every good answer. However, I have to chose only one answer as the Accepted Answer and because mVChr provided valuable improvements of my code, I would like to mark this answer as the Accepted Answer. Thank you all.Arrival

© 2022 - 2024 — McMap. All rights reserved.