Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting Javascript in a page from a Chrome extension : concurrency issue?

I am taking part in the development of a Chrome extension.

At some point, we need to run some static non-generated code which has to run in the context of the page and not of the extension.

For simple scripts, there is no problem, using either $.getScript(chrome.extension.getURL(....)) either script = document.createElement('script'); ... document.body.appendChild(script);

For more complex scripts, we'd need sometimes to incluque jquery itself, or some other script definition (because of dependencies).

In this latter case, though, despite the fact that Javascript is supposedly single threaded, it seems that JQuery is not parsed entirely when the dependend script are run, leading to the following

Uncaught ReferenceError: $ is not defined

Am I wrong when assuming that JScript is single-threaded? What is the correct way to inject scripts in a page when there are dependencies between those scripts? (e.g. script X uses a function defined in script Y)

like image 583
Frédéric Donckels Avatar asked Mar 24 '12 12:03

Frédéric Donckels


2 Answers

You could use the onload event for the script....

function addScript(scriptURL, onload) {
   var script = document.createElement('script');
   script.setAttribute("type", "application/javascript");
   script.setAttribute("src", scriptURL);
   if (onload) script.onload = onload;
   document.documentElement.appendChild(script);
}

function addSecondScript(){
    addScript(chrome.extension.getURL("second.js"));
}

addScript(chrome.extension.getURL("jquery-1.7.1.min.js"), addSecondScript);
like image 101
PAEz Avatar answered Nov 01 '22 02:11

PAEz


Appending a script element with src attribute in the DOM doesn't mean that the script is actually loaded and ready to be used. You will need to monitor when the script has actually loaded, after which you can start using jQuery as normal.

You could do something like this:

    var script = doc.createElement("script");
    script.src = url;
    /* if you are just targeting Chrome, the below isn't necessary        
    script.onload = (function(script, func){
        var intervalFunc; 

        if (script.onload === undefined) {
            // IE lack of support for script onload

            if( script.onreadystatechange !== undefined ) {

                intervalFunc = function() {
                    if (script.readyState !== "loaded" && script.readyState !== "complete") {
                        window.setTimeout( intervalFunc, 250 );

                    } else {
                        // it is loaded
                        func();

                    }

                };

                window.setTimeout( intervalFunc, 250 );

            } 

        } else {
            return func;
        }

    })(script, function(){

       // your onload event, whatever jQuery etc.
    });
    */
    script.onload = onreadyFunction; // your onload event, whatever jQuery etc.

    document.body.appendChild( script );
like image 35
Niklas Avatar answered Nov 01 '22 02:11

Niklas