Search code examples
javascriptloading

how to wait until a dynamically included javascript file is properly loaded?


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.


Solution

  • 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>