Todd
Todd

Reputation: 1481

Javascript/Node.js async loop

I'm having trouble with the async nature of node in general. Can someone help me with this block of code. For various reasons I can only insert 1 row at a time into the database I am working with. And actually, it would be even better if I could add a short delay to only insert 1 row per second into the database.

Here is a short section of my js code.

console.log('*** Inserting Records ***')
insertPromises = []
_.each(dbRecords, function (item) {
    var insertItem = buildRecord(item)
    insertPromises.push(conn.create(insertItem))
})
Promise.all(insertPromises).then(function (res) {
    _.each(res, function (item) {
        if (!item.success) {
            console.log("### Error ### " + JSON.stringify(res[i].errors))
        }
    })
    console.log('*** Inserted ' + res.length + ' Contacts')
})

My main question is how can I force the loop to wait for the conn.create promise to resolve before continuing the loop? And is there a way to slow the loop to 1 iteration per second?

Upvotes: 0

Views: 117

Answers (2)

Alex Michailidis
Alex Michailidis

Reputation: 4143

Instead of using the recursion code posted above, you could check the async/await model.

An example of using this would be:

async function processRecords(dbRecords) {

    for (let item of dbRecords) {
        try {
            let insertItem = buildRecord(item)
            await conn.create(insertItem)
            await delay(1000)
        } catch (e) {
           //handle error...
        }
   }

}

function delay(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms))
}

processRecords(dbRecords)

This is es7 code and you need babel compiler to transform it.

It is probably better to use something like this if you find hard to keep up with promises and you want to stick with sync-like code.

Upvotes: 1

Jbird
Jbird

Reputation: 2886

A simple solution would be to keep track of an "insert count", that is, the current number of successfully inserted records. This will be your array pointer. Use a method to create each, individual promise and increment your "insert count" by 1 on each successful response.

let insertCount = 0;

function insertNextRecord() {
    conn.create(buildRecord(dbRecords[insertCount]).then(function(res){
        insertCount += 1;
        insertNextRecord();
    }).catch(function() {
        console.log('Error while inserting record ' + insertCount);
    });
}

insertNextRecord(); 

This is not tested and I'm making several assumptions about the code you're not showing.

This example assumes:

  • dbRecords is an array
  • conn.create returns a promise object

To explicitly add a delay, you could use a timeout within the then method like so:

let insertCount = 0;

function insertNextRecord() {
    conn.create(buildRecord(dbRecords[insertCount]).then(function(res){
        insertCount += 1;
        setTimeout(function() {
            insertNextRecord();
        }, 500);
    }).catch(function() {
        console.log('Error while inserting record ' + insertCount);
    });
}

insertNextRecord(); 

I should also say it's unfortunate that you have to do it this way. This will be very slow when dealing with many inserts.

Upvotes: 1

Related Questions