Javascript AJAX include file witth eval
Asked Answered
L

3

4

Suppose I have

1) a HTML document.

2) This HTML document loads Javascript file "code.js" like this:

<script src="code.js">

3) User clicks button which runs "fetchdata" function in "code.js",

4) "fetchdata" function looks like this:

var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState==4) {
        myjsdata = xmlhttp.responseText;
    }
}
xmlhttp.open("GET", 'http://www.example.com/data.js', false);
xmlhttp.send(null);

...

Now how do I do the following successfully:

I want to insert/eval my Javascript in a way, so all functions in "code.js" including "fetchdata" and functions defined above/below can access the data (structures, declarations, pre-calculated data values etc.) in "data.js".

(If this was possible, it would be idea since I could wait loading the actual JS data file until the user explicitly requests it.)

Loanloanda answered 26/1, 2012 at 3:8 Comment(1)
Do you use jQuery, or have any specific reason not too? It can drastically help with things like ajax calls, so you don't have to check readystate and status, which you should have been checking for 200 on success.Hithermost
H
10

jQuery always has something for everything:

http://api.jquery.com/jQuery.getScript/

Loads a javascript file from url and executes it in the global context.

edit: Oops, didn't see that you weren't using jQuery. Everyone is always using jQuery...

Just do:

var scrpt = document.createElement('script');
scrpt.src='http://www.example.com/data.js';
document.head.appendChild(scrpt);
Hithermost answered 26/1, 2012 at 3:10 Comment(14)
Thanks! So instead of using Ajax/related, I can use your code in "code.js" ... And functions inside "code.js" will have immediate access to all variables etc. defined inside "data.js"? I will try it out now :)Loanloanda
@Tom, Yes, adding a script element to the head executes it.Hithermost
"Step 1: If you are using jQuery, call the getScript function. Step 2: If you are not using jQuery, start using jQuery and return to Step 1."Bugg
This seems to work in IE9, but it does not seem to work in FireFox. After applying your "appendChild" code, "fetchdata" immediately tries to call a function (that initializes data) in the just appended "data.js" file... But FireFox says this call is defined.Loanloanda
@Malvolio It is important for me to keep footprint as small as possible.Loanloanda
I meant FF says the call "is not defined". I have also tried to use "dochead.insertBefore(my_script_data, dochead.firstChild);", no luck :(Loanloanda
if i had to choose between using a buggy multi-liner script (which may not be scalable and robust) and using a proven library with a one-liner call, i'd go for the library approach - they were made so that you don't have to reinvent the wheel.Nobles
Argh, I had forgot this. Oh well, I will work out something :) I would prefer your solution over the Ajax one since yours will also work when running offline. (I don't know if my code will run on CDs, websites or whereever, so it is a big advantage with your solution.)Loanloanda
Combining Walkerneo with solutions listed in Joseph link below has solved my problems. Thanks everyone! :)Loanloanda
@Loanloanda -- I was mostly kidding, but I have to agree with what Joseph said. The stuff in a framework is often very difficult to get right. Good frameworks often have ways to strip them down to just what you need.Bugg
@Malvolio -- In this specific case space is of high importance to me. (Even if it may turn out I am overly worrying about this.) In addition, I also need to distribute my code together with my executable, and I prefer to limit 3rd party stuff for this reason as well. (Basicly I have a program that pre-calculates keyword/phrase scores, importance of pages, other content metrics etc. and then throws it all into size-optimized Javascript data files giving reasonable quality site-wide online/offline search.)Loanloanda
Ah,here's what you want to do: don't write your library without a framework, write it with several frameworks. Withough too much difficulty, you can make a version the works with jQuery, another works with YUI, and so on. Your customers are likely to be using one anyway, and if one isn't, it is perfectly reasonable to require them to start.Bugg
In my dealing with customers, things just have to work out-of-the-box if you want to get the most sales. Anyhow, in this case, I don't really see the need for framework. The proposed solutions suggested here worked out great, only took a few lines of code, and I learned something at the same time :) But yes, I know JQuery is popular and where I ever to make a larger Javascript application, frameworks like JQuery would be a natural fit, I agree! :)Loanloanda
But the script I'm trying to get is jQuery. What now?Foxing
N
5

i think you should take a look at this site

this site talks about dynamic loading and callbacks (with examples) - where you can call a function in the loaded script after it loads. no jQUery, just pure JS.

Nobles answered 26/1, 2012 at 5:33 Comment(3)
Using both methods listed in "Detecting Load Completion" (+ making sure I do not risk getting called with both) actually solved the rest of my problems in newest versions of IE,FF,Opera,Chrome ... Thanks :)Loanloanda
This worked perfect. I was trying to load jQuery... so I didn't have jQuery to begin with to load jQuery.Foxing
Works perfectly. i let here my implementation.Hobard
F
2

This depends on a lot of factors, but in most cases, you will want to load all of your code/html/css in one sitting. It takes fewer requests, and thus boast a higher perceived performance benefit. Unless your code file is over several Megabytes big, loading it when a user requests it is unnecessary.

In addition to all of this, modifying innerHTML and running scripts via eval can be very cumbersome and risky (respectively). Many online references will back this point. Don't assume that, just because a library is doing something like this, it is safe to perform.

That said, it is entirely possible to load external js files and execute them. One way is to stick all of the code into a newly created script tag. You can also just try running the code in an eval function call (though it isn't recommended).

address = "testscript.js";

var req = (window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");
if(req == null) {
    console.log("Error: XMLHttpRequest failed to initiate.");
}
req.onload = function() {
    try {
        eval(req.responseText);
    } catch(e) {
        console.log("There was an error in the script file.");
    }
}
try {

    req.open("GET", address, true);
    req.send(null);

} catch(e) {
    console.log("Error retrieving data httpReq. Some browsers only accept cross-domain request with HTTP.");
}
Facile answered 26/1, 2012 at 3:35 Comment(5)
The thing is my data.js is between 200-500kb. I prefer to only load it when needed. However, where does "eval" put the code into scope / declaration order? Do I just need to call "eval" and all functions/vairables etc. will be immediately available?Loanloanda
And in theory there is no upper limit on data file size... Could easily be much lager if people were okay with it... However, for now I operate with a "minimize size and time" mentality :)Loanloanda
eval executes in the global scope I believe. It really is that simple to run a foreign script, which is why it is so dangerous.Facile
Just wanted to say thanks for this suggestion as well! I upvoted all responses since they have all been valuable :)Loanloanda
I am new to JS and I have been searching for this for a couple of days!!! You are a LIFE saver!Cammie

© 2022 - 2024 — McMap. All rights reserved.