1

I use an include function to dynamically include javascript files/headers/libraries.

The problem is that it seems loading the file happens in a multi-threaded way (tested on Chrome v102) and the js file is not yet loaded when I immetiately use functionnality after that.

Example with jQuery:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8"/>
        <script type="text/javascript">
            var include_once = function(url) {
                /*
                [additional code to check if 'url' was already included]
                */
                var script = document.createElement("script");
                script.type = "text/javascript";
                script.src = url;
                document.head.appendChild(script);
            }
            
            include_once("https://code.jquery.com/jquery-3.6.0.min.js");
        </script>
    </head>
    <body>
        <script type="text/javascript">
            /*
            ok if I wait 'long enough' but is arbitrary
            */
            setTimeout(function(){
                $(document).ready(function(){
                    console.log("ready (timeout)");
                });
            }, 10);
            
            /*
            how to wait until window.$ is defined?
            */
            $(document).ready(function(){
                console.log("ready");
            });
        </script>
    </body>
</html>

This code will likely give you a $ is not defined error, and ready (timeout) will be logged to the console.

How can I make my script wait until window.$ !== undefined here ?

I tried while(window.$ === undefined) {} but it completely blocks the script and $ is never defined.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
PinkTurtle
  • 6,942
  • 3
  • 25
  • 44
  • 1
    See https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement#dynamically_importing_scripts – T.J. Crowder Jun 04 '22 at 11:20
  • @mplungjan it *does* work with a timeout. Test it. – PinkTurtle Jun 04 '22 at 11:21
  • So add an eventListener to the script - more examples here: https://www.google.com/search?q=defer+script+until+other+script++has+loaded+site:stackoverflow.com – mplungjan Jun 04 '22 at 11:22
  • `let script = document.createElement("script"); script.type = "text/javascript"; script.addEventListener("load", function() { console.log(\`${url} loaded\`) }); script.src = url; document.head.appendChild(script);` – mplungjan Jun 04 '22 at 11:24
  • 1
    You can easily achieve both targets with querySelector and promises https://jsfiddle.net/c7a1u6td/ – Christopher Jun 04 '22 at 11:35
  • @Christopher can you explain what the regexp does please? – PinkTurtle Jun 04 '22 at 12:13
  • It searches and escapes `"` with a backslash inside the url to avoid errors with invalid query selector. – Christopher Jun 04 '22 at 22:33

1 Answers1

1

you can promisfy the loading process, by creating a promise on first script and then on the second script check if the promise is resolved.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8"/>
        <script type="text/javascript">
            var isLoaded = new Promise((res,rej) => {
              function include_once(url) {
                  /*
                  [additional code to check if 'url' was already included]
                  */
                  var script = document.createElement("script");
                  script.type = "text/javascript";
                  script.onload = () => res()
                  script.onerror = () => rej()
                  script.src = url;
                  document.head.appendChild(script);
              }
              include_once("https://code.jquery.com/jquery-3.6.0.min.js");
          })
          
        </script>
    </head>
    <body>
        <script type="text/javascript">
            isLoaded.then(() => {
              $(document).ready(function(){
                console.log("ready");
            });
            })
        </script>
    </body>
</html>
Alan Omar
  • 4,023
  • 1
  • 9
  • 20