4

Are there any alternatives to using eval to immediatly run remote & trusted javascript code.

function load(filePath) {
    var o = $.ajax({
        url: filePath,
        dataType: 'html',
        async: false 
    }); 

    eval(o.responseText);
}

load("somePath");
// run a function that relies on the code from o.responseText being loaded
doSomethingWithCode();

I'm aware that synchronous loading of javascript is adviced againts. But if there is no choice are there any cross browser alternatives for the use of eval above.

[Edit]

To clarify in more detail the code being loaded is a self executing function. Which needs to execute before doSomethingWidthCode. It's also being loaded from the server on the same domain hence its trusted.

Raynos
  • 166,823
  • 56
  • 351
  • 396

4 Answers4

4

Dynamic script text insertion is the only alternative to eval.

var head    = document.getElementsByTagName('head')[0] || document.documentElement,
    nscr    = document.createElement('script');

    nscr.type           = 'text/javascript';
    nscr.textContent    = o.responseText;
    nscr.setAttribute('name', 'dynamically inserted');
    nscr.onload         = nscr.onreadystatechange = function() {
              if( nscr.readyState ) {
                   if( nscr.readyState === 'complete' || scr.readyState === 'loaded' ) {
                      nscr.onreadystatechange = null;
                       doSomethingWithCode();
              }
              else {
                  doSomethingWithCode();
              }
    };

    head.insertBefore(nscr, head.firstChild);

Only thing to mention: textContent is not available in InternetExplorers. You would need to use .text instead there, so a little detection for that makes it cross-browser compatible.

edit

To have a syncronous loading dynamic script tag, you could add nscr.async = true;. Anyway, this only works in cutting edge browsers.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Tried that. Does not work synchronously. That will run the code in o.responseText after the function terminates. – Raynos Jan 05 '11 at 14:29
  • @Raynos: can use an `onload` / `onreadystatechange` handler ? – jAndy Jan 05 '11 at 14:32
  • @jAndy would that not make the thing asynchronous. I might be able to use them but I'm not sure whether It would help. – Raynos Jan 05 '11 at 14:36
  • I've edited the code segment above. I can only work with the load function and most ensure that the code has been run when the function ends. – Raynos Jan 05 '11 at 14:38
  • @Raynos: you're right. You `could` add `nscr.async = true;`, but it's only available in cutting edge browsers. I guess there is no real alternative to `eval` to run it syncronously. – jAndy Jan 05 '11 at 14:40
  • The nice thing about appending a script tag is that you can go across domains, which you can't do in ajax. – Zeki Jan 05 '11 at 14:44
  • I wouldn't call it stealing code, you can hotlink images, css, and just about anything else too. But the neat thing about javascript tags is that you can use them to dynamically load data into the page from a remote domain. The only limit is that it must be a script file, so you can't scrape a remote page and parse it. But if there is someone (most likely yourself) who publishes data in a json format, then you can fetch that data in from a remote domain using this technique. – Zeki Jan 05 '11 at 15:00
1

I would use JSONP in this case. Raymond Camden provides and excellent introduction to the concept.

A quick example of using JSONP in this situation is available at http://playground.itcouldbe9.com/syncjsonp/.

James Sumners
  • 14,485
  • 10
  • 59
  • 77
  • @Raynos, because JSONP uses a *callback*, and thus can be loaded asynchronously. – David Tang Jan 05 '11 at 14:29
  • 1
    @Box9: he clearly states in the question that he's looking for synchronous execution. Hence the fact that it can be loaded asynchronously makes no difference here. Honestly, this answer reminds me too much of [this](http://www.doxdesk.com/img/updates/20091116-so-large.gif) – ircmaxell Jan 05 '11 at 14:33
  • If there is no the loaded url is within the same domain is there any need to JSONP ? And I do not wish to load asynchronously. – Raynos Jan 05 '11 at 14:34
  • @ircmaxell, @Raynos, as far as I can tell, the only reason for synchronous execution given in the question is that there's some dependant code. A callback solves that quite nicely, while addressing Raynos' issue of "being aware that synchronous loading of javascript is advised against". In defence of @jsumners, I didn't see any other "issue" being raised in the question. – David Tang Jan 05 '11 at 14:36
  • This answer is not even close to that ridiculous response, ircmaxell. He wants an alternative to running code through eval. The only other option is to insert a new script into the document to have the interpreter interpret the code. Downloading a new script from a server, inserting it into the document, and having the code executed is colloquially known as "JSONP." – James Sumners Jan 05 '11 at 14:40
  • @Box9 Apologies, I gave the illusion that the dependant code was mutable and could be moved to a callback. If possible I would like to avoid moving it and merely place the loading and executing in the above `load` function – Raynos Jan 05 '11 at 14:40
  • @Raynos, if the dependant code cannot be moved, is that simply because it is in a different file? If so, can the contents of the whole file be wrapped in a function? – David Tang Jan 05 '11 at 14:45
  • @jsumners At least I now, know what the JSONP term means. – Raynos Jan 05 '11 at 14:47
  • @Box9 It can be moved to a callback, but I rather stick to using `eval` then move it to a callback. I don't think its _that_ evil. – Raynos Jan 05 '11 at 14:49
  • @Raynos, I have updated my answer with an example that I think will work for your described situation. – James Sumners Jan 05 '11 at 15:12
  • @jsumners: For the record, it wasn't me who downvoted. I just was commenting on the brevity and tone of the original answer. I'm sorry if you took offense in it. – ircmaxell Jan 05 '11 at 17:19
0

You can have your code returned wrapped inside a function, and when the request completes, execute that function. For example, this is your remote code:

function hi(){alert('hi');}

And then when your request is complete, you can inject that code into a javascript tag and then call the function hi()

Colum
  • 3,844
  • 1
  • 22
  • 26
0

why not use a callback?

eval('(function(){' + o.responseText + ';})(); doSomethingWithCode();')

EDIT:

OK then try this:

var o = $.ajax({
    url: filePath,
    dataType: 'html',
    async: false
    success: function(responseText){
        eval('(function(){' + responseText + '})()');
        doSomethingWithCode();
    });
}); 

I think the only option left would be polling:

(function(){
    if (o.responeText)
        doSomethingWithCode();
    else 
        setTimeout(arguments.callee, 13);
})();
qwertymk
  • 34,200
  • 28
  • 121
  • 184
  • 1
    That is the exact same as the code sample above and doesn't really add anything. – Raynos Jan 05 '11 at 14:33
  • Afraid I rather not move the `doSomethingWithCode` line to a callback. It's an option but not a clean solution with the current setup I have. – Raynos Jan 05 '11 at 14:45
  • just because the o.responseText string is not null does not mean it has been executed. The polling option doesn't really do anything useful. But you could append some mechanism to ensure the above `load` function does not end until the code has been loaded. – Raynos Jan 05 '11 at 14:55