Leonardo Alves Leonardo Alves - 7 months ago 30
Javascript Question

Bluebird promise loop

I am trying to get all records from a DynamoDB table using promises. The problem is that DynamoDB do not return all items in one call I have to make multiple calls. If LastEvaluatedKey is not null means that I need to make another call with that key to get the remaining records. In my code I am checking that and resolving only after LastEvaluatedKey is null. But the

console.log("done")
is not being executed.

Here is my code:

function query(params) {
return new Promise(function(resolve, reject) {
docClient.query(params, function(err, data) {
if (err) {
reject(err)
} else {
resolve(data);
}
});
})
}

function getAllRecords(params, combinedData) {
return new Promise(function(resolve, reject) {
query(params)
.then(function(data) {
if(!combinedData) {
combinedData = [];
}
combinedData.push(data.Items);
if(data.LastEvaluatedKey) {
params.ExclusiveStartKey = data.LastEvaluatedKey;
getAllRecords(params, combinedData)
}
else {
resolve(combinedData);
}
})
})


}

getAllRecords(params)
.then(function() {
console.log('done')
})
.catch(function(error) {
console.log(error);
})


It's probably a misconception on how promises work from my part. If someone can give me an idea how to make this work. That would be great.

Answer
if(data.LastEvaluatedKey) {
    params.ExclusiveStartKey = data.LastEvaluatedKey;
    getAllRecords(params, combinedData)
}

This branch of your code, neither resolves nor rejects the current promise. So, you are recursively creating unresolved promises.

Instead, you can use the returned promise as the resolved value, like this

if(data.LastEvaluatedKey) {
    params.ExclusiveStartKey = data.LastEvaluatedKey;
    resolve(getAllRecords(params, combinedData));
}

You can check this, like this

new Promise((resolve, reject) => resolve(Promise.reject(1)))
    .then(console.log)
    .catch(function(err) {
        console.error('Error', arguments);
    });

Now, resolve would resolve the current promise as a rejected promise with the reason 1, so the control will reach catch handler.

In your case, instead of Promise.reject you will have the recursive call, which returns a promise.