karthik
karthik

Reputation: 355

How to write synchronous function in Node.js

I am newbie to Node.js and I am struggling with asynchronous calls.

In this below code I have an array of feeds for example(1,2,3..). each feed can contain multiple images and now i want to delete the images from the folder and from database.

What i have done so far:

for(var i=0; i<feedArr.length; i++){
    var feedId = feedArr[i].feedid;
    var listFeedImageQuery  = "select imageUrl from feedImages where feedId='"+feedId+"'";
    var deleteFeedImagesQuery = "delete from feedImages where feedId='"+feedId+"'";
    model.client.query(listFeedImageQuery,function(err,result){
        if(result.rows.length > 0){
            for(var j=0; j<result.rows.length; j++){
                fs.unlink(result.rows[j].imageurl, function(err) {
                    if(err)
                        console.log(err);
                });
            }
            model.client.query(deleteFeedImagesQuery,function(err,result){
                if(err)
                    console.log(err)
                else
                    console.log(feedId +' were removed'); // last feedId only gets removing from database
            });
        }   
    });
}

Here I am able to delete the images from the image storage folder, but I am unable to delete the records from the database. Only the last feed record is getting deleted. The rest of the feedImage records are in database.

I researched something about async modules, but i don't know how to apply it to this issue.

Upvotes: 1

Views: 3727

Answers (2)

Ethan Wu
Ethan Wu

Reputation: 87

for (var i = 0; i < 10; i++) {
  console.log('sync', i);   
  setTimeout(function () {
    console.log('wrong async', i)
  }, 1);
}


for (var i = 0; i < 10; i++) {  
  setTimeout((function (j) {
    console.log('right async', i)
  })(i), 1);
}

enter image description here

Figure it out, maybe you will know where you was wrong.


For your issue, you can extract the async code as a function, like this:

function deleteImages(feedId) {
    var listFeedImageQuery  = "select imageUrl from feedImages where feedId='"+feedId+"'";
    var deleteFeedImagesQuery = "delete from feedImages where feedId='"+feedId+"'";
    model.client.query(listFeedImageQuery,function(err,result){
        if(result.rows.length > 0){
            for(var j=0; j<result.rows.length; j++){
                fs.unlink(result.rows[j].imageurl, function(err) {
                    if(err)
                        console.log(err);
                });
            }
            model.client.query(deleteFeedImagesQuery,function(err,result){
                if(err)
                    console.log(err)
                else
                    console.log(feedId +' were removed'); // last feedId only gets removing from database
            });
        }   
    });
}

for(var i=0; i<feedArr.length; i++){
    var feedId = feedArr[i].feedid;
    deleteImages(feedId);
}

For the more complex issue, if you don't want the callback hell, try async or bluebird

Upvotes: 1

libik
libik

Reputation: 23049

this is a common problem when switching to callback framework from the "standard" one.

This is how it works, first it synchronously run this

for(var i=0; i<feedArr.length; i++){
    var feedId = feedArr[i].feedid;
    var listFeedImageQuery  = "select imageUrl from feedImages where feedId='"+feedId+"'";
    var deleteFeedImagesQuery = "delete from feedImages where feedId='"+feedId+"'";
    model.client.query(listFeedImageQuery,function(err,result){
        //to be executed later
    });
}

The method model.client.query is pushed with each cycle to the "stack of asynchronous calls", therefore in the moment when the all these queries are executed, the feedId is equal to feedArr[feedArr.length-1].feedid

One simple workaround is to wrap it around methods with parameter and then call them immediately.

for(var i=0; i<feedArr.length; i++){        
    (function(feedId) {
       var listFeedImageQuery  = "select imageUrl from feedImages where feedId='"+feedId+"'";
       var deleteFeedImagesQuery = "delete from feedImages where feedId='"+feedId+"'";
       model.client.query(listFeedImageQuery,function(err,result){
           //to be executed later
       });
    })(feedArr[i].feedid);
}

Now it should work.

Upvotes: 1

Related Questions