Search code examples
javascriptpromisedomcontentloaded

Run two separate functions on DOMContentLoaded


I have a website which has two files; main.js and loading.js

loading.js waits for DOMContentLoaded, then clears a loading screen cover.

main.js also waits for DOMContentLoaded, but also waits for loading.js to finish its DOMContentLoaded, then executes some more code.

I need to write some code (possibly using Promises?) which allows this to happen.

Here is my code:

loading.js

document.addEventListener('DOMContentLoaded', () => {
    var loadingCover = document.querySelector('#loading-cover');
    loadingCover.style.display = 'none';
});

main.js

document.addEventListener('DOMContentLoaded', () => {
    /* Wait for loading.js */
    console.log("Do stuff");
});

I've done some research with Promises, but I can't wrap my head around how they could work in this situation.

I've tried using a Promise which is resolved inside loading.js. main.js then waits for that Promise to be resolved before executing its own code.

Ideally, this would be the code:

loading.js

const loadingPromise = new Promise();
document.addEventListener('DOMContentLoaded', () => {
    var loadingCover = document.querySelector('#loading-cover');
    loadingCover.style.display = 'none';
    loadingPromise.resolve();
});

main.js

/* Terrible example */
loadingPromise.addEventListener('resolve', () => {
    console.log("Do stuff");
});

Solution

  • One way to do is by creating a Promise, then saving the resolve function to be later called like this:

    //
    // createPromise() returns an object containing the promise
    // itself and the function to be called in order to resolve
    // said promise
    //
    function createPromise() {
        let ret = {}
    
        ret.promise = new Promise((resolve) => {
            ret.resolve = resolve
        })
    
        return ret
    }
    
    window.main_promise = createPromise()
    
    document.addEventListener('DOMContentLoaded', () => {
        var loadingCover = document.querySelector('#loading-cover');
        loadingCover.style.display = 'none';
    
        // add some artificial delay
        setTimeout(window.main_promise.resolve, 1000);
    });
    

    In loading.js:

    document.addEventListener('DOMContentLoaded', async () => {
        /* Wait for loading.js */
        await window.main_promise.promise;
    
        console.log("Do stuff");
    });
    

    This will block execution of console.log("Do stuff"); until window.main_promise.resolve(); is called somewhere in code.

    Of course, main.js needs to be loaded before loading.js in order for this to work.