mpen
mpen

Reputation: 282895

How to inject a script synchronously?

Many of suggested that I just utilize the .onload and fire a callback once the script is ready. That doesn't work for me. I'm writing a function and it expects an element immediately, not at a later time. Here's what I've got:

webdriver.By.sizzle = function(selector) {
    driver.executeScript("if(typeof Sizzle==='undefined'){var s=document.createElement('script');s.type='text/javascript';s.src='https://raw.github.com/jquery/sizzle/master/src/sizzle.js';document.head.appendChild(s);}");
    return new webdriver.By.js("return Sizzle('"+selector.replace(/"/g,'\\"')+"')[0]");
};

I want to inject Sizzle (if it's not already included) and then return an HtmlElement. It can busy-wait if it needs to, but it has to return an HtmlElement.

All the answers here basically just said "don't do it", but I can't think of another way.

This is a selector for selenium web driver for JavaScript.


driver.executeScript will take arguments. I wonder if I can pass in a webdriver.promise and have it invoked when the script is loaded...? I don't know how to 'fufill' a promise.

Upvotes: 0

Views: 1392

Answers (3)

mpen
mpen

Reputation: 282895

It's a bit slow, but I think I found a solution:

webdriver.By.sizzle = function(selector) {
    driver.executeScript("return typeof Sizzle==='undefined'").then(function(noSizzle) {
        if(noSizzle) driver.executeScript(fs.readFileSync('sizzle.min.js', {encoding: 'utf8'}));
    });
    return new webdriver.By.js("return Sizzle('"+selector.replace(/"/g,'\\"')+"')[0]");
};

I've just downloaded the script and I'm injecting the whole thing inline. This way I don't need to wait for anything.

Upvotes: 0

why aren't you just including sizzle as an on-page script requirement. Just stick

<script src="sizzle.js"></script>

somewhere in the head and it'll get loaded before your other script runs. To do this dynamically, just append the script to the head. http://jsfiddle.net/nQePg has a demonstrator that shows you script execution halts while the injection is being parsed and evaluated.

Upvotes: 0

jfriend00
jfriend00

Reputation: 707456

The best choice here would be to redesign/restructure your code to handle asynchronous loading of Sizzle and return your result via a callback function. This is how javascript is designed. It does NOT have a "good" way of loading remote resources synchronously.

The only way I know of to load a remote resource like a JS file synchronously is to use a blocking AJAX call to load the resource (will be subject to same origin restrictions so you will have to host it on your server) and then once you've loaded the resource into memory, you can execute it (to cause it be loaded). Then, you can call the functions defined in it and return their result.

The reason this is bad is that the blocking ajax call will lock up the browser for an indeterminate amount of time while the remote resource is loaded. That type of design is bad for the user experience.


The only other choice I can think of is to make sure, during the page loading, that all required resources are already specified so that they are already preloaded when your script then requires them. Loading a remote resource on demand is what causes the async problem.

Upvotes: 2

Related Questions