Guillaume Robbe
Guillaume Robbe

Reputation: 666

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.

Upvotes: 17

Views: 21708

Answers (3)

Shanoor
Shanoor

Reputation: 13672

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.

Upvotes: 38

I was having the same problem, my Promise.all(list), results in an array of undefined, I used the same approach of adding a return to my function.

Upvotes: 0

Guillaume Robbe
Guillaume Robbe

Reputation: 666

So here the solution of my problem:

function addText(queries) {
  return Promise.all(queries.map(function(query) {
    return new Promise(function(resolve, reject) {

      models.queries.findById(query.queryId, { raw: true, attributes: ['query'] })
      .then(function(queryFetched) {
         query.text = queryFetched.query;
         resolve(query);
      }, reject);

    });
  }));
};

Upvotes: 1

Related Questions