0

I've been encountering an issue regarding JS promise use, and hopefully it is simply that I am missing something very obvious.

Essentially, I attempt to read multiple JSON files at once and push their content to an array belonging to another object, then perform operations on the elements on this array. Therefore, the array needs to be filled before operations are attempted on them. However, despite me using promises to theoretically make sure the order is correct, it seems what I've written fails at doing that.

How do I fix this issue?

Here are snippets of the code I'm using, where the issue arises:

This is the function where I push the extracted objects to my array:

function pushNewRoom (ship, name_json_folder, elem, id) {
  let promiseRoom = new Promise ((resolve, reject) => {
    let newRoom = gf.getJSONFile(name_json_folder + '/' + elem + ".json")
        // note: getJSONFile allows me to grab a JSON object from a file
      .then(
        (data) => {
          data.name = elem;
          ship.rooms.push(data);
          return data;
      }).then((newRoom) => {
          resolve(newRoom);
      }).catch((reject) => {      // if the JSON file doesn't exist a default object is generated
        let newRoom = new Room (elem, id);
        ship.rooms.push(newRoom);
        resolve(newRoom);
      });
  });
  return promiseRoom;

}

And this is the part that calls that function and performs the operations I need after that:

exports.generateRoomsByLayout = function (name_json_folder, ship)
{


        ship.rooms = [];
        console.log("reached step 1");
        // First execution step: get a JSON file
        gf.getJSONFile(name_json_folder + "/_base_layout.json")
        .then(function (shipmode){
        // Note: shipmode is a JSON object that acts as a blueprint for the operations to follow.
        // Importantly here, it contains an array, layout, containing the names of every other JSON file I will need to perform the operations.
        console.log("reached step 2");


        Promise.allSettled(shipmode.layout.map(function (elem, index){pushNewRoom(ship, name_json_folder, elem, index);})
              // note: this is where my issue happens
                ).then(function (){
                console.log("reached step 3");
                 // Operations on the results that were pushed to ship.rooms by pushNewRoom()
              }).then(function (shipmode) {
                console.log("reached step 4");
                // More operations on the results
                

              }).catch((err) => {

              });
          return Promise.resolve(shipmode);
        }).catch(function (errRejection) {
          // Error handling
          console.log(errRejection);
        });

};

The issue happens right at the Promise.allSettled() line. Rather than waiting for the promises supposedly generated with ship.layout.map(), that would then become an iterable array, the program continues on.

I suppose this is because Promise.allSettled() does not wait for the array to be generated by map() before moving on, but have been unable to fix the issue, and still doubt that this is the explaination. Could anyone enlighten me on what I am doing wrong here?

If what I'm asking is unclear then please do tell me, and I'll try my best to clarify.

edit: I suspect it is linked to Promise.allSettled() not waiting until map() fills the array to consider every promise inside the array settled, as its length seems to be 0 right at step 3, but I am not sure.

  • Note that you rarely need to create a new promise. For instance, your first function could just `return gf.getJSONFile(...)`. You might also want to rethink the pattern of pushing objects to array properties on other objects in an async manner like that. Instead, get the data returned by all of the promises and `reduce` them into the property. – Heretic Monkey Aug 10 '20 at 20:14
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in `pushNewRoom`! – Bergi Aug 10 '20 at 20:26
  • Can you please format the code with proper indentation? It's really hard to figure out the nesting of your promise chains. – Bergi Aug 10 '20 at 20:28
  • @Bergi : Sorry, I don't know whats the usual indentation for promise chains :/ I'll check this link out. – sointaminn Aug 15 '20 at 16:51
  • @sointaminn Doesn't matter whether there is a "usual" indentation for promises or not, but it should at least be consistent. Or just throw it into an autoformatter. – Bergi Aug 15 '20 at 16:54

1 Answers1

0

Nevermind, I'm an idiot.

The map() method's callback (?) won't (obviously) return an object (and therefore, a promise) if you do not tell it to. Therefore,

shipmode.layout.map(function (elem, index){pushNewRoom(ship, name_json_folder, elem, index);})

needs to be

shipmode.layout.map(function (elem, index){return pushNewRoom(ship, name_json_folder, elem, index);})

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92