MeetJoeBlack
MeetJoeBlack

Reputation: 2904

node.js Callback was already called error

I need to call callback inside recursive function when iterator bigger then some value or I succesfully write requested image to file, I try to do it like that , but I recieve error:

Error: Callback was already called.

Here is my code:

async.each(products,  function(product, callback) {
            var i = products.indexOf(product);
            var pathNames = pathNormalizer(product.sku + "");

            setTimeout(
                function () {
                    fetchImage(pathNames[0],pathNames[1], 0, 0, function(err){
                        console.log("CALLBACK"); callback()
                    });
                }, 150 * (i + 1) // where they will each progressively wait 150 msec more each
            );
        }, function(err) {
            console.log("ASYNC EACH FINISH");

        }
    );

function fetchImage(url, localPath, index, iteration, fetchCallback) {

var extensions = ['jpg', 'png', 'jpeg', 'bmp' , ''];
var fileExtension;
if(extensions[index] === '' ) {
    fileExtension = extensions[0];
}else{
    fileExtension = extensions[index];
}

if (iteration > 2 || index === extensions.length) { fetchCallback(null)};  

request.get(url + extensions[index], { encoding: null }, function(err,response,body) {
    if(err || undefined === response){   
        setTimeout(function(){
            console.log('Error URL : ' + url + extensions[index] + ' ' +  err);
            fetchImage(url, localPath, index, iteration,fetchCallback);
        }, 200);
    }else{
        if(response.statusCode === 200) {
            fs.writeFile('s' + localPath + fileExtension, body, 'binary', function(err){    //INTENTIONAL ERROR HERE (invalid path)
                if (err){
                    setTimeout(function(){
                        console.log('Image saving error : ' + err  + url + extensions[index]);
                        fetchImage(url, localPath, index, iteration +1, fetchCallback);
                    }, 500);
                }else {
                    console.log('Image was successfully downloaded ' + localPath + fileExtension);
                }
            });

        }else {
            fetchImage(url, localPath, index + 1, iteration, fetchCallback);  //try another extension
        }
    }
});
}

Upvotes: 0

Views: 509

Answers (2)

cs04iz1
cs04iz1

Reputation: 1815

As I see it there is a chance that

 if (iteration > 2 || index === extensions.length) {
        fetchCallback(null)
    };

is executed and then moves to the request.get part, which will be calling callback again at some point.

Upvotes: 1

DARK_DUCK
DARK_DUCK

Reputation: 1777

There is at least one problem in the code :

If the condition iteration > 2 || index === extensions.length is true then fetchCallback will be called 2 times so your async callback will be called 2 times.

I suggest you change if (iteration > 2 || index === extensions.length) { fetchCallback(null)}; by if (iteration > 2 || index === extensions.length) { return fetchCallback(null)};

Upvotes: 0

Related Questions