Polite gentleman

I hear that people “don’t really understand Promises” at least a few times a month and every time I think that I am not one of those people.

Here I will be describing a case my team faced recently and the way it was resolved. Just saying though, I am not a big fan of callbacks and the “old way” of implementing Promises, but I do like async/await way.

There will be description of the steps that we have gone through, so if you need the final solution — scroll till the end of the article.

Problem description

So first, let me describe the problem. We had an array of values which we needed to iterate over and pass each element of the array to a function as one of arguments (function returns a Promise). Second argument is a database connection. At the end we needed to pass array of values (not promises) to another function. In addition, the function was returning an object with a value that was to be used inside the same loop. The main aim was to get the best performance results and good code readability.

Initial version

First version of the code:

The above case had a nice async/await syntax, while we pretended to use Promises. asyncForEach() is awaiting for callback, immediately resolves it and the resolved value is pushed to the finalArray. In this case the value from asyncFunction() is resolved immediately, so we don’t really benefit from Promises. Here we just had a pretty and mainstream async/await syntax :). In order to improve the performance we needed to push all Promises to an array and then resolve it all at once like it is shown here.

But in this case our code would look similar to this:

This approach would improve the performance a bit. However, readability would be worse and additional code would appear (another loop). Also, we still did not get the best performance (iterating over resolved values would require additional time/resources). So, it was decided to not implement it and try to come up with a more “promisified” way.

Callback time has come?

It is better to give instructions to a Promise of actions that needs to be done once it will be resolved. Here comes then(). We can push function call to an array without resolving it and include instructions of value actions into the callback. Which means that once the Promise will be resolved (after forEach() loop) we don’t really need to worry about another loop to iterate over each of the values, because it is already there during the resolution. So here is the code:

Callback gets a Promise and once it reaches Promise.all(), the callback is resolved. No additional loop, no time waste, no additional code. The performance in this case was significantly better than in the initial one.

Don’t worry if it still does not work: probably you’re still using a MySQL connection with Promises. Use Pool instead. Connection is opened upon every loop’s iteration, which is not “healthy” considering the fact that asyncFunction() is running in parallel (almost) to each of the myArray’s elements. Using createPool() will have many connections to the database at the same time and will reuse connections that have finished the previous run. Pool is a perfect solution for async operations (unless you do not think about limitations and/or are trying to kill the application’s connection to the MySQL database). But then() is “the old way”, so not good enough.

Final solution(s)

So how can we get rid of the callback, improve readability and keep the same performance? Here is the final solution:

Or:

If you are enjoying adding new npm packages check out bluebird , it has Promise.map(), which can do both — Promise.all() and map().

Conclusion

The final solution has the best performance, code readability was good enough and no extra code. This case helped me to understand Promises a bit better, but still I am not sure if I am one of those who “really does understand promises”.