1

I feel like there must be a simple, searchable answer to this, but try as I might, I am unable to find the solution to this simple problem. I am new to Promises and callbacks, so I am probably using the wrong search terms.

I have multiple DOM objects that have HTML loaded in via jquery's load function. The order the pieces are loaded in the page does not matter - however, I want to do some tasks only after ALL of them have completed loading.

Promise.all seemed like a great solution, something such as this:

// what I'd like to be able to do.

function init_page() {

    var init_tasks = [];
    init_tasks.push($("#divA").load("page1.html"));
    init_tasks.push($("#divB").load("page2.html"));
    init_tasks.push($("#divC").load("page3.html"));

    await Promise.all(init_tasks);

    // do stuff here    

}

However, load() returns a callback function, not a Promise object, so this does not work.

I made a wrapper function (shown below), which wraps load's returned callback function in a Promise, so I can use the above approach. Unfortunately, with the way I've written it, the Promises never resolve. I figure I am probably doing something very obviously wrong, but I can not figure out what. (Do I need to be returning something other than the Promise? Do I need to define resolve and reject cases?)

// incorrect "Promise wrapper" attempt

function loadPromiseWrapper(dom_id, filename) {
    return new Promise(function(resolve, reject) {
        $(dom_id).load(filename);

        // what am I missing here?
    }); 
}

// revised init_page function that calls my incorrect "Promise wrapper"

function init_page() {

    var init_tasks = [];
    init_tasks.push(loadPromiseWrapper("divA", "page1.html"));
    init_tasks.push(loadPromiseWrapper("divB", "page2.html"));
    init_tasks.push(loadPromiseWrapper("divC", "page3.html"));

    await Promise.all(init_tasks);

    // never gets here because none of the Promises resolve

}

What am I missing? How do I properly wrap the returned callback of jquery's load function in to a Promise, so that I can use Promise.all and wait for all the individual pieces to complete?

bikz
  • 415
  • 4
  • 11
  • Don't use `$(..).load(..)` instead, use `$.ajax(...).done((data)=>$("#divA").html(data))` to get the promise. – freedomn-m Sep 26 '21 at 16:59
  • Ivar, thank you for suggesting this. I had actually seen that link - Benjamin's answer (Part 2: 2. Plain callback) is what I was looking at. however, I am uncertain what would be the resolve and reject variables that are being passed, in his getUserDataAsync example. I don't believe jquery load() function has these - do I need to create them manually, by monitoring the callback of load()? – bikz Sep 26 '21 at 17:03
  • freedomn-m - I see, so the approach suggested here is to use $.ajax to load the html file, and then place it in the DOM object manually (kind of re-creating the load() function itself). Since ajax returns a Promise object already, then I could use Promise.all on all the pieces. Interesting - seems like this could work - going to try this. I'm still curious if there's a way to wrap the callback of 'load' in a Promise and rely on the load function though. – bikz Sep 26 '21 at 17:06
  • The `resolve` and `reject` parameters passed to the `Promise` constructor callback. They should be invoked inside the `load` callback function. (Or passed as the callback function itself.) Gabriele's answer below shows you how it should be done. – Ivar Sep 26 '21 at 17:07
  • FYI use `@`name to send that user a notification of your comment. eg @Ivar – freedomn-m Sep 26 '21 at 17:14
  • Thank you both! Was able to get this working, simply by passing dummy 'resolve' variable to jquery's load function, as suggested by @Gabriele. Finally got this working! – bikz Sep 26 '21 at 17:30

1 Answers1

2

.load can take more parameters and one of them is a complete callback. That is where you should put the resolve

function loadPromiseWrapper(dom_id, filename) {
    return new Promise(function(resolve, reject) {
        $(dom_id).load(filename, resolve);
    }); 
}
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • WOW. @Gabriele Petrioli - that WORKED! THANK YOU! The only thing is, I'm unsure why, in a way... resolve and reject seem to be dummy variables with no content. Looking at the documentation for 'load', this resolve argument, is a function to be executed upon success. So is this resolve just essentially doing nothing in the success case? (But still serving the purpose of having a resolve?) – bikz Sep 26 '21 at 17:28
  • `resolve` and `reject` are functions provided by the promise that you can call to specify either `resolve` or `reject` that promise. The value you pass to `resolve` will be the one passed to the `then` functions you call on the `Promise`. So by passing the reference to that function to `.load` it will be called when the `.load` completes, and so will resolve your own promise. – Gabriele Petrioli Sep 26 '21 at 17:34
  • You should have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise – Gabriele Petrioli Sep 26 '21 at 17:35