javascriptpromisees6-promise

How to use promises to wait until a Javascript library has loaded?


I am building a solution in which multiple Javascript libraries are dynamically loaded at different points in time based on the user's interaction. After the libraries are loaded, the scripts in the library are executed.

For example:

let script1 = '<script src="' + some_script_url_1 +'"></script>';
$("head").append(script1);
let script2 = '<script src="' + some_script_url_2 +'"></script>';
$("head").append(script2);
let script3 = '<script src="' + some_script_url_3 +'"></script>';
$("head").append(script3);

And then some code will execute a function that's defined inside the loaded script:

scriptFunction(); // This function is defined in the dynamically loaded library

The problem is that sometimes the script will not be loaded before the function tries execute. This causes errors like "scriptFunction not found". How can I wait for each library to load before executing the script? Can this be done with promises?


Solution

  • Here is a function that returns a promise that resolves when a script has loaded:

    function loadScript(src) {
        return new Promise((resolve, reject) => {
            const script = document.createElement("script");
            script.onload = resolve;
            script.onerror = reject;
            script.setAttribute("src", src);
            document.head.appendChild(script);
        });
    }
    
    const urls = [
        "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/luxon/3.0.1/luxon.min.js"
    ];
    
    Promise.all(urls.map(loadScript)).then(ready,
                                           err => console.log("Error loading", err.target.src));
    
    function ready() {
        console.log("all loaded");
        console.log($.fn.jquery);
        console.log(luxon.DateTime.now().toString());
    }