1

I have a chain of functions for grabbing some JSON data, then inserting the data into a database. I want to wait for all of the inserts to complete, so I am trying to use Promise.all(). I know that Promise.all() needs an array (or iterable) of promises.

Here is my chain:

fetchBody().then(parseBody).then(prepareInserts).then(insertAll).then(function() {
    console.log('done')
}); // Error handling and more stuff here

My code is hanging on the prepareInserts function:

// Returns an array of promises, which will be iterated over in Promise.all();
const prepareInserts = function (data) {
    return new Promise(function (resolve, reject) {
        const promises = data.map(function (d) {
            return new Promise(function (resolve, reject) {
                connection.query(queryString, [d.a, d.b, d.c, d.d], function (error) {
                    if (error) {
                        reject(error);
                        return;
                    }
                    resolve();
                });
            });
        });
        resolve(promises);
    });
};

I think I have a fundamental misunderstanding of how I should be laying out the prepareInserts function; the queries are being executed there, which is not what I want. I want them to be inserted in the last function in the chain:

const insertAll = function (promises) {
    return Promise.all(promises);
};
Tyler
  • 17,669
  • 10
  • 51
  • 89
  • 2
    What is this `data` function doing? – Bergi Nov 02 '15 at 13:31
  • 1
    Where are you getting multiple promises here? – Bergi Nov 02 '15 at 13:31
  • `data.map(...)` perhaps?? – Amit Nov 02 '15 at 13:31
  • This is a [`Promise` constructor antipattern](http://stackoverflow.com/q/23803743/1048572), but I'm not sure whether fixing that is enough to get you what you actually want. – Bergi Nov 02 '15 at 13:32
  • @Bergi oops that was supposed to be `data.map` – Tyler Nov 02 '15 at 13:32
  • "*the queries are being executed there, which is not what I want.*" - where (when) else would you want them to be executed? What difference does it make? – Bergi Nov 02 '15 at 13:33
  • what do you want the internal promises (queries...) to resolve to? – Amit Nov 02 '15 at 13:35
  • 2
    Regarding your fundamental misunderstanding, have a look at [Is Promise.all processing in parallel or sequentially?](http://stackoverflow.com/a/30823708/1048572) – Bergi Nov 02 '15 at 13:35
  • @Bergi thanks that is a helpful link. I guess that I just don't understand where to incorporate the call to `Promise.all()` in my code. – Tyler Nov 02 '15 at 13:37
  • And what the correct pattern is for dynamically creating/starting a lot of patterns simultaneously. – Tyler Nov 02 '15 at 13:39
  • I just read your `// Error handling` comment, so leaving aside that you have got a `catch` and the fact that the formation is a little messy, this should work as-is - [Babel REPL Demo](http://bit.ly/1Q1Q5FJ) – CodingIntrigue Nov 02 '15 at 13:50

1 Answers1

2

I think this is what you want:

const doInserts = data => {
  return Promise.all(data.map(d => 
     new Promise((resolve, reject) => {
       connection.query(queryString, [d.a, d.b, d.c, d.d], error => {
         if (error) {
           reject(error);
           return;
         }
         resolve(/* to what?? */);
       });
     }));
  });
};

fetchBody().then(parseBody).then(doInserts).then(function() {
  console.log('done')
});

You return a Promise.all() promise that resolves when all internal promises are resolved (with no value?). Each internal promise is created by mapping a data item (from data) to a promise, which is resolved or rejected depending on the query result.

If you could promisify connection.query outside of this code, it would make for a cleaner result, where you map to "promisifiedQuery" directly.

Amit
  • 45,440
  • 9
  • 78
  • 110
  • Thanks this is exactly what I was trying to do. Is it important for their always to be a value in the `resolve()` call? For example, what parameter would you pass on a successful `db.insert` ? – Tyler Nov 02 '15 at 13:51
  • 1
    It's not important if you don't use it. If you only want to know that there was no error, that's fine as it is. If you want more details in your next "`then`", you might want to resolve to inserted row count (if that's applicable) – Amit Nov 02 '15 at 13:53