Search code examples
javascriptarraysasynchronouspromisees6-promise

Promise.all is returning an array of undefined and resolves before being done


I am having trouble with a function returning an Array of undefined.

Here is code:

classMethods.getQueries = function(models, dbId, dateStart, dateEnd) {
  return new Promise(function(resolve, reject) {
    // Fetch database.
    .then(extractQueries, reject)
      .then(sortQueries, reject)
      .then(onlyTen, reject)
      .then(addText, reject)
      .then(function(queries) {
        console.log("getQueries finished", queries); // Array of 10× undefined!
        resolve(queries);
      }, reject);

    // Functions here.
  });
};

Everything is fine until the addText function:

function addText(queries) {
  return Promise.all(queries.map(function(query) {
    models.queries.findById(query.queryId, {
      raw: true,
      attributes: [ "query" ]
    })
      .then(function(queryFetched) {
        query.text = queryFetched.query;
        console.log(query);
        
        return Promise.resolve(query);
      }, function(error) {
        return Promise.reject(error);
      });
  }));
};

This is giving me an output like:

"getQueries finished" [ undefined ×10 ]

10×
[query database]
{ queryId: "…", text: "…" }

I have no idea why the promise is returned while the loop is not finished.


Solution

  • Promise.all accepts an Array of Promise objects. You’re getting an Array of undefined because you’re not returning any Promise in your map callback:

    function addText(queries) {
      return Promise.all(queries.map(function(query) {
        // Add `return` here or the `map` returns an Array of `undefined`.
        return models.queries
          .findById(query.queryId, {
            raw: true,
            attributes: [ "query" ]
          })
          .then(function(queryFetched) {
            query.text = queryFetched.query;
            console.log(query);
            
            return Promise.resolve(query);
          }, function(error) {
            return Promise.reject(error);
          });
      }));
    };
    

    A primitive value such as undefined will resolve immediately in Promise.all, therefore it resolves before any of the Promises in your callback resolve.