Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS wait for callback to complete execution inside a for loop

I am having an array which consist of 3 data which I need to insert in pouchdb, so I'm using a for loop to insert the data, but the problem is it is not inserting complete data because the loop finishes before callback.

for(var i=0;i<data.length;i++){
   var jsondoc=doc1;//document
    console.log(i)  //getting console for all data. eg:1,2,3
    console.log(data[i])//getting console for all data. eg:hi, hello

    jsondoc.messages.push({msg: data[i]});   //updating message, here need to be done somthing           
                      db.put(jsondoc, function(err2, response2){
                         if (err2) { console.log(JSON.stringify(err2)); }
                            console.log("this is not repeating") ;                                    
                       });

}
like image 899
Atul Verma Avatar asked Jul 10 '26 05:07

Atul Verma


2 Answers

Since the db insertion runs async, you cannot put the loop on hold until the operation completes. One thing that you can do is to serialise the db inserts with a helper function like this:

function insertItem(data, i, completeCallback) {
    // check if we still have items to send
    if(i < data.length) {
        var jsondoc=doc1;//document
        //updating message, here need to be done somthing
        jsondoc.messages.push({msg: data[i]});   
        db.put(jsondoc, function(err2, response2){
            if (err2) { 
                console.log(JSON.stringify(err2)); 
            } 
            // recursively call to push the next message
            insertItem(data, i+1, completeCallback);
        });
    } else {
        // no more items to send, execute the callback
        if(typeof completeCallback === "function") {
            completeCallback();
        }
    }
}

You'll have to update your code so that instead of continuing the execution after the call of the function, to pass that code into the callback of the pushMessage function, so if your original code looks like this:

// ... code before the loop
for(var i=0;i<data.length;i++){
    // ... original body of the loop
}
// ... code to execute after the loop and that currently causes problems

you'll need to change it like this:

// ... original code that was before the loop
insertItem(data, 0, function() {
    // ... original code hat was executed after the loop and that caused problems
    // but now it gets executed after all items were inserted in db
}

Another alternative would be to send all inserts in parallel and perform a join() on those operations; you'll still need the callback workaround though. Something along the lines:

function insertItems(data, callback) {
    var remainingItems = data.length;
    if(remainingItems === 0 && typeof callback === "function") {
        callback();
    }         
    for(var i=0;i<data.length;i++){
        var jsondoc=doc1;//document
        console.log(i)  //getting console for all data. eg:1,2,3
        console.log(data[i])//getting console for all data. eg:hi, hello

        jsondoc.messages.push({msg: data[i]});   //updating message, here need to be done somthing           
        db.put(jsondoc, function(err2, response2){
            if (err2) { console.log(JSON.stringify(err2)); }
            remainingItems--;
            if(remainingItems === 0 && typeof callback === "function") {
                // I know, code redundancy :P
                callback();
            }                                     
        });

    }
}

The usage of this second function is the same as for insertItem.

like image 148
Cristik Avatar answered Jul 13 '26 19:07

Cristik


If I understand you correctly, your problem is a scoping issue. jsondoc or data[i], or whichever variable is causing the problem, is changed before your callback can complete.

Take a look at this jsFiddle, which shows how to solve such a scoping problem.

for(var i = 0; i < 3; i++){
    (function(){
        var j = i;
        setTimeout(function(){
            callback(j)
        }, 500);
    })();
}

If you look at your js console when the jsFiddle runs you'll see that the first loop prints 3 times 3, which is the finishing value for i. While the second, where we store the value to a new variable inside a new scope, outputs 1, 2, 3 as expected.

like image 24
Robin Avatar answered Jul 13 '26 20:07

Robin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!