debugjavascriptMinor
Writing a user's profile image to disk using nested Node.JS closures
Viewed 0 times
imagediskusernodewritingprofilenestedusingclosures
Problem
I am writing non-blocking code as it should be in Node.JS. If I want run function A after B I do it using callback.
But I find this style guide:
Use closures, but don't nest them. Otherwise your code will become a
mess.
Right:
Wrong:
How deep should my closures be? Specifically, I'd like to consider this sample:
But I find this style guide:
Use closures, but don't nest them. Otherwise your code will become a
mess.
Right:
setTimeout(function() {
client.connect(afterConnect);
}, 1000);
function afterConnect() {
console.log('winning');
}Wrong:
setTimeout(function() {
client.connect(function() {
console.log('losing');
});
}, 1000);How deep should my closures be? Specifically, I'd like to consider this sample:
exports.profileImage = function(req, res) {
var id = req.params.user_id;
userProvider.get(id, function(err, user){
if (err) throw err;
userProvider.getImageById(user['image_id'], function(err, image) {
if (err) throw err;
userProvider.writeImageToDisk(image, function(err, path){
if (err) throw err;
res.sendfile(path);
});
});
});
};Solution
First of all, you are correct. One way to prevent deep nesting is to pull out the callback into it's own named function. This allows you to only be as deep as 2-3 levels in blocks of code.
Another way to do it is by using flow-control libraries which take advantage of the concept of Futures/Deferreds/Promises. There are a lot of ways to call them, but they are the same thing most of the time.
The basic concept is that they usually stack up callbacks via utility functions and then run them, depending on the result of the previous or depending on the used utility function. The code will look linear and synchronous, but it actually is running async and the library controls the flow of calls and results. In jQuery, you can do something like
function task1(){
async1(task2);
}
function task2(){
async1(task3);
}
function task3(){
async1(task4);
}Another way to do it is by using flow-control libraries which take advantage of the concept of Futures/Deferreds/Promises. There are a lot of ways to call them, but they are the same thing most of the time.
The basic concept is that they usually stack up callbacks via utility functions and then run them, depending on the result of the previous or depending on the used utility function. The code will look linear and synchronous, but it actually is running async and the library controls the flow of calls and results. In jQuery, you can do something like
//Run an addition in the server
$.get('add.php',{
op1 : 1,
op2 : 2
})
.then(function(result){
//get the addition result (3) and multiply it on the server (another async)
return $.get('multiply.php'{
op1 : result,
op2 : 3
});
})
.then(function(result){
//get the multiplication result (9) and divide it on the server (another async)
return $.get('divide.php'{
op1 : result,
op2 : 9
});
})
.done(function(result){
console.log(result); //1
});Code Snippets
function task1(){
async1(task2);
}
function task2(){
async1(task3);
}
function task3(){
async1(task4);
}//Run an addition in the server
$.get('add.php',{
op1 : 1,
op2 : 2
})
.then(function(result){
//get the addition result (3) and multiply it on the server (another async)
return $.get('multiply.php'{
op1 : result,
op2 : 3
});
})
.then(function(result){
//get the multiplication result (9) and divide it on the server (another async)
return $.get('divide.php'{
op1 : result,
op2 : 9
});
})
.done(function(result){
console.log(result); //1
});Context
StackExchange Code Review Q#35307, answer score: 4
Revisions (0)
No revisions yet.