17

I have a site that loads information using the XMLHttpRequest when a user clicks a link. The system works well but I would like to be able to execute JavaScript gathered in this process.

This is a problem as I would like to download the scripts 'on demand' if it were, rather than loading them all when the page is loaded.

Thanks for any help

5 Answers 5

15

I believe the recommended solution is something like this:

function include(scriptUrl)
{
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", scriptUrl);
    xmlhttp.onreadystatechange = function()
    {
        if ((xmlhttp.status == 200) && (xmlhttp.readyState == 4))
        {
            eval(xmlhttp.responseText);
        }
    };
    xmlhttp.send();
}

Or something like it.

However, be wary of this approach. It's vulnerable to cross-site scripting, which can open you (and your users) up to all sorts of nastiness. You'll want to take suitable precautions.

Sign up to request clarification or add additional context in comments.

7 Comments

Didn't see your comment when posted. You're completely right. However I think you have to check readyState value in onreadystatechange handler like it is shown here w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp.
@Insomniac: Duly noted, and thanks. Post fixed! Wouldn't work very well if the stream ended in the middle of a statement now, would it?
I'm pretty sure that you still need to change your condition to if (xmlhttp.status == 200 && xmlhttp.readyState == 4)
And even better to use something like this plugins.jquery.com/project/rloader to avoid eval'ing.
While I like jquery, personally, it's not suitable for every environment. I'd personally have my lips stapled to the wall if I introduced it into the product at work. So, you show folks both approaches and enjoy the benefits of increased knowledge.
|
8

Recently I found the answer (It works in Chrome, in another browsers it was not tested).

You can create dataURL string and put it into src attribute of script element.

var xhr = XMLHttpRequest(),
    doc = document;
xhr.open('GET', pathToJSFile, true);
xhr.onload = function () {

    var script = doc.createElement('script'),
        base64 = 'data:application/javascript;base64,';
    try {
        base64 += btoa(data.responseText);
    } catch (e) {
        // script file may contain characters that not included in Latin1
        var symbols = data.responseText.split('');
        for (var i = 0, l = symbols.length; i < l; i++) {
            var symbol = symbols[i];
            // here we are trying to find these symbols in catch branch
            try {
                btoa(symbol);
            } catch (e) {
                var code = symbol.charCodeAt(0).toString(16);
                while (code.length < 4) {
                    code = '0' + code;
                }
                // replace original symbol to unicode character
                symbols[i] = '\\u' + code;
            }
        }
        // create new base64 string from string with replaced characters
        base64 += btoa(symbols.join(''));
    } finally {
        script.src = base64;
        // run script
        doc.body.appendChild(script);
    }

};
xhr.send();

You can subscribe to xhr.onprogress to show progress bar.

Update. You can download your script file as blob, and then create blob-url.

var xhr = XMLHttpRequest(),
    doc = document;
xhr.responseType = 'blob';
xhr.open('GET', pathToJSFile, true);
xhr.onload = function () {

    var script = doc.createElement('script'),
        src = URL.createObjectURL(xhr.response);

    script.src = src;
    doc.body.appendChild(script);
};
xhr.send();

2 Comments

But if you choose this way of inserting a script, via createElement('script') and setting the 'src' attribute, why not just load the script directly via 'src' ? No need to use XMLHttpRequest here.
@renardesque This would allow you to load a script where you need to provide header information.
6

You can run script downloaded in form of a string using

eval()

However I would recommend you to add new

<script src='..'></script>

to your document and have a callback which will be called when it will be downloaded. There are many utils and jquery plug-ins for that.

2 Comments

eval'ing from XHR is less dangerous than injecting a <script> due to same-origin policies placed on XHR (which are not present with <script>). However, setting up <script> is often simpler.
I totally agree that both approaches have a security issues, but if you want dynamic script loading you don't have too much to choose from :) Also eval()'ed script are not cached and can badly affect performance if you have a big script.
1

I had the challenge on a mobile web-project, the magic was to set "overrideMimeType". This has been verified to work on Android 4.1 to Android 6.0.

var head = document.getElementsByTagName('head');
var injectedScript = document.createElement('script');
head[0].appendChild(injectedScript);

var myRequest = new XMLHttpRequest();
myRequest.onreadystatechange = function() {
  if (myRequest.readyState == 4 && myRequest.status == 200) {
        injectedScript.innerHTML = myRequest.responseText;
    //run a function in the script to load it   
  }
};

function start(){
    myRequest.open('GET', 'javascript-url-to-download', true);
    myRequest.overrideMimeType('application/javascript');
    myRequest.send();
}

start();

Comments

0

You would need to use eval to parse the javascript from the XHR, note that this is EXTREMELY dangerous if you don't have absolute trust in the source of the javascript.

1 Comment

This is just a social bandwagon autocomment: using words "extremely" and "absolute" based on belief, without any explanation. For fundamentalist coders I suggest to replace eval is evil commandment to less inquisitory thou shalt not parse user input. Abiding this, from security point of view, parsing script from text is like adding script with same-origin policy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.