0

I'm new to promise, and trying to use promise in a for loop.

function query(queryString, keywords) {
  var defer = q.defer();
  connection.query(queryString + '"' + keywords + '"', function (err, rows) {
    if (err) {
      defer.reject(err);
    } else {
      defer.resolve(rows[0]);
    }
  });
  return defer.promise;
}

q.all([
  query(testQuery, 'test1'),
  query(testQuery, 'test2')
]).then(console.log, console.log);

The above code is working and returns an array of results.

What I am trying to do is to use a for loop so I don't need to write the query every time.

query(testQuery, 'test1'),
query(testQuery, 'test2'),
query(testQuery, 'test3'),
query(testQuery, 'test4')

And here is my updated code:

function query(queryString, keywords) {
  var defer = q.defer(),
      results = [];
  for (var i = 0; i < keywords.length; i++) {
    connection.query(queryString + '"' + keywords[i] + '"', function (err, rows) {
      if (err) {
        defer.reject(err);
      } else {
        results.push(rows[0]);;
      }
    });
  }
  defer.resolve(results);
  return defer.promise;
}

var tests = ['test1', 'test2'];

q.all(query(testQuery, tests)).then(console.log, console.log);

And the above code is not working which returns an empty array.

This seems not to be the correct way to use a for loop for promises. So in this case, how can I return an array of promises after a for loop?

Thanks.


Updated version (Based on @Bergi's comment):

function query(queryString, keywords) {
  var defer = q.defer();
  connection.query(queryString + '"' + keywords + '"', function (err, rows) {
    if (err) {
      defer.reject(err);
    } else {
      defer.resolve(rows[0]);
    }
  });
  return defer.promise;
}

var tests = ['test1', 'test2'],
    results = [];

for (var i = 0; i < tests.length; i++) {
  results.push(query(testQuery, tests[i]));
}

q.all(results).then(console.log, console.log);

This is working, but I wonder if there is a way to include the for loop inside the query function. As I have to write a for loop every time when using this method.

Victor Xiong
  • 315
  • 1
  • 4
  • 13
  • 1
    Move the loop outside your `query` function. And create an array that you can pass to `Q.all` like you did in your first snippet. – Bergi Nov 25 '14 at 16:13
  • If you want a function around that loop, introduce a second function. Try not to stuff everything into a single function. – Bergi Nov 25 '14 at 17:04

2 Answers2

0

It should look something like this:

function query(queryString, keywords) {
    var promiseArr = [];

    for (var i = 0; i < keywords.length; i++) {
        var deferred = $q.defer();
        promiseArr.push(deferred.promise);

        connection.query(queryString + '"' + keywords[i] + '"', function (def) {
            return function (err, rows) {
                if (err) {
                    def.reject(err);
                } else {
                    def.resolve(rows[0]); // what is rows and why just rows[0]???
                }
            };
        }(deferred));
    }

    return promiseArr;
}

var tests = ['test1', 'test2'];
q.all(query(testQuery, tests)).then(console.log, console.log);
Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
0

Here is a version that uses the underscore library to get your desired results. You are going to have to use something that adds a level of scoping. Both native map and underscore map will work

function query(queryString, keywords) {
    return _.map(keywords, function(keyword) {
        return Q.promise(resolve, reject) {
            connection.query(queryString + '"' + keyword + '"', function (err, rows) {
                if (err) {
                    reject(err);
                } else {
                    resolve(rows[0]);
                }
            });
        };
    });
}

var tests = ['test1', 'test2'],
    results;


q.all(query(testQuery, tests).then(console.log, console.log);
RadleyMith
  • 1,313
  • 11
  • 22
  • @amir-popvich answer works now as well. We have basically the two opposite ways you can achieve the same result. – RadleyMith Nov 25 '14 at 17:13