0

I'm having this strange problem, there is probably something very basic that I miss here...
I'm coding Javascript in NodeJs with Express.

Consider this simple route.

client.get('/test', function(req, res, next) {
    return next(new Error('This is a error'));
    console.log ('This code will not be executed');
    res.send('This code will not be executed');
});

As you probably see this route will directly call next() and pass control to a error handler. The error will be output (res.json) and the request ended. Only the first row in the route will be executed... Just like it should be.

Lets now change the first row in the router to this:

client.get('/test', function(req, res, next) {
    hlpr.deadSimple('stop here', function (err) {
        if (err) return next(err);
    });
    console.log ('I dont want this code to be executed, but it will be...');
    res.send('This code shall not be executed either');
});

function deadSimple looks like this and is exported from hlpr.js

module.exports.deadSimple = function (val, callback) {
    if (val === 'stop here') {
        callback(new Error('This is a error!')); 
        // I have also tried "return callback(new Error('This is a error!'));" 
    }
};

If i try this code an error is created and it seems that the Error handler is called, it output the Error, but then is seems like control is passed back to the route handler function!... because the console.log is executed.

Why are my deadSimple function passing control back to the route handler?

And how should i write this to work in the way that i want... That is if deadSimple generate an error, this error will trigger a direct return from the route handler function, pass control to error handler, which output the error... And NOT passing control back to the route handler!

EDIT

There was something very basic i missed here, namely that the return statement in the anonymous function that is passed as a callback only return from itself, and not from the surrounding route handler function.

If I move console.log and res.send into the callback they wont be executed because the callback function is returned before they have a chance of being executed. When the callback contains only synchronous code (as this does), it will be executed completley before the code below the callback gets executed.

To show my point... this works as intended:

client.get('/test', function(req, res, next) {
    var foo = null;
    hlpr.deadSimple('stop here', function (err) {
        foo = err;
    });
    if (foo) return next(foo);

    console.log ('This text WILL not be seen');
    res.send('This text WILL not be seen either');
});

2 Answers 2

1

Try putting the other code inside the event handler, so it'll only run if the if statement is false:

client.get('/test', function(req, res, next) {
    hlpr.deadSimple('stop here', function (err) {
        if (err) return next(err);
        console.log ('I dont want this code to be executed, but it will be...');
        res.send('This code shall not be executed either');
    });
});
Sign up to request clarification or add additional context in comments.

1 Comment

This works like a charm!... Aha!!! My return in the route handler only return from the surrounding anonymous callback function and not the actual route handler function, right! =)
1

You have it almost right. In your example :

client.get('/test', function(req, res, next) {
    hlpr.deadSimple('stop here', function (err) {
        if (err) return next(err);
    });
    console.log ('I dont want this code to be executed, but it will be...'); //this line is executed right away
    res.send('This code shall not be executed either'); 
});

It first executes hlpr.deadSimple, which expects a callback. But if you want to wait for this callback before executing the next functions, you need to place them inside your callback function :

client.get('/test', function(req, res, next) {
    hlpr.deadSimple('stop here', function (err) { //everything inside this function will be executed only when it calls back
        if (err) return next(err);
        console.log ('I dont want this code to be executed, but it will be...');
        res.send('This code shall not be executed either');
    });

});

Let me try to explain using a simple analogy (it exists somewhere on this site, but I can't find it...) :

You're at work, and you need a document from your colleague Jim across the city in order to fill in a form. You pickup your phone and call Jim, who says : 'I'll have a look and I'll call you back'. Then you hang up the phone and go for a coffee break. After a while, Jim calls you back, and gives you the info. You can then fill up your form.

The situation above can be written as :

Jim.call(function(info){
    fillForm(info)        //that's the part you do only when your colleague calls back
}
haveBreak();  // That's the action you take just after calling Jim, before he calls you back

6 Comments

Yes, Isn't the problem that the return on row three only return from the anonymous callback, and not from the outer route handler. But maybe this is what you meant, with other word... =P
the return will return when the callback is answered, but it's already too late, the res.send() has already been executed
Hmmm... But this callback only contain synchronous code. It should be run to completion before the code below is executed. Right?
Check out my attempt at an explanation
Even though I love your analogy with the colleagues, you forget that this callback only contains synchronous code, therefore it will be no haveBreak() before I have the document in my hands. Your solution to move the console.log and res.send into the callback works! They will not executed. But only because of the return statement, it has nothing to do with a delayd callback, because this callback is not asynchronous and therefore not delayed. =) Take a look at my edit and code example in my question above.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.