Q:

Nested async callbacks in JavaScript

I'm trying to learn exactly how async works in JavaScript. 
In the example below I'm doing a nested database lookup inside the callback of another async database call (in the example I'm just using setTimeout)
The way I'm trying to keep track of when I'm done going through all the products including the nested database call is by incrementing a variable called index and checking for index == fake_data.length. 
This database library does not support Promises out of the box, so I'm really unsure what else to do. This just doesn't seem like the right way of doing it.
const fake_data = [{ type: 4 }, { type: 4 }, { type: 1 }, { type: 1 }, { 
type: 4 }, { type: 3 }, { type: 2 }];

const products = [];

function test() {
    setTimeout(() => {
        let index = 0;
        fake_data.forEach(product => {
            if (products.filter(p => p.type == product.type).length == 0) {
                products.push(product);
                setTimeout(() => {
                    index++;
                    if (index == fake_data.length) {
                        test2();
                    }
                }, 400)

            }
            else {
                index++;
            }
            console.log("index", index);
        })
    }, 1200);

}

function test2() {
    console.log(`Wooow, i have some many unique types here`);
    products.forEach(p => console.log(p.type));
}

I feel like I have missed something very basic  somewhere...

A:

You can convert your callback style code to promise based. Have a look here http://bluebirdjs.com/docs/api/promise.promisify.html
Or you can use this snippet https://gist.github.com/joelnet/ece690e942223954b1b7997ba3b1cb00#file-promisify-js
function promisify(func) {
  return (...args) =>
    new Promise((resolve, reject) => {
      const callback = (err, data) => err ? reject(err) : resolve(data)

      func.apply(this, [...args, callback])
  })
}

