node.js - Does calling the callback terminate the current function - javascript

I want to call a util function that might encounter an error. In case of an error the process function should be terminated. The only way to throw an error properly is the callback function.
I would terminate the function by returning, but since I am in the util function, the process function will continue after the util() call.
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
return callback("something unexpected happened");
}
}
function process(callback) {
util(callback);
console.log("This should not be printed if an error occurs!");
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
// terminate the process function somehow?
}
});

Does calling the callback terminate the current function?
No, a callback is just a regular function. It might of course throw an exception (although that is despised).
I want to call a util function that might encounter an error. In case of an error the process function should be terminated.
For that, you need to check in the callback what did happen and act accordingly. You could use process.exit for termination.
function myProcess(callback) {
util(function(err, result) {
if (err) {
callback(err);
} else {
console.log("This should not be printed if an error occurs!");
callback(null, result);
}
});
}
myProcess(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1);
}
});
Notice that promises could simplify this a lot, as they distinguish between success and error callbacks. util would have to return a promise for that:
function util() {
return new Promise(function(resolve, reject) {
// do something asynchronous
if (err)
reject("something unexpected happened");
else
resolve(…);
});
}
function myProcess() {
return util().then(function(res) {
console.log("This should not be printed if an error occurs!");
return res;
});
}
myProcess().catch(function (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1); // you might not even need this:
throw err; // The node process will by default exit with an unhandled rejection
});

I suggest you make a few changes to your code
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
callback("something unexpected happened");
return false;
}
return true;
}
function process(callback) {
if(!util(callback)) return;
console.log("This should not be printed if an error occurs!");
}

This seems like a good time to use a Promise, promises are Javascript's way of forcing a synchronous function. Basically you set it up like this:
var util = new Promise(function(resolve, reject) {
/* do some stuff here */
if (someCondition) {
resolve("With a message");
} else {
reject("with a message");
}
}
function process() {
util.then(function() {
console.log("Won't call if there is an error");
}).catch(function() {
console.log("There was an error, Bob");
});
}

No, you will want to do something like this:
function util(callback) {
// do something synchronous
if (err) {
throw new Error('Something unexpected happened');
}
callback(); // only execute callback if an error did not occur
}
function process(callback) {
try{
util(callback);
console.log("This should not be printed if an error occurs!");
} catch(error){
process(error);
}
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1)
}
});

Related

will `return` be caught on error in a try/catch block?

I have a try/catch block within which I run my synchronous function call, I wonder why it won't be caught by the catch if the function return an Error. In this case I have a known issue in mySyncFunction and I don't want to throw on that, because I want the test function to catch that
function test() {
try {
return mySyncFunction();
} catch (error) {
console.error('my error message', error);
return [];
}
}
function mySyncFunction() {
try {
// Do stuff
const expectedIssue = true;
if (expectedIssue) {
return Error('the known issue happended');
}
} catch (e) {
throw Error(e)
}
}
console.log(test());
If there is no error occuring during the call of this.mySyncFunction(args) it will returns normally. However, if there is an exception raised during this call, it will simply go directly to the catch, console.error your error and return [].
You're not throwing an Error, you're returning one. Errors and other exception are only caught when you throw them, not by simply being around.
The correct way to actually see the exception being caught is
function test() {
try {
return mySyncFunction();
} catch (error) {
console.error('my error message', error.message); // notice error.message
return [];
}
}
function mySyncFunction() {
throw new Error('my error'); // notice throw
}
console.log(test());

Unable to throw error in angular js promise

I have an as promise as :
try {
myPromise().then(function(){
console.log("ok");
}, function(err) { throw err; });
} catch(e) {
console.log("error");
}
now my control goes to the function(err) and it throws the error but the error is not caught in catch().
Because promises are asynchronous, flow control doesn't work the way you're thinking it will. Your try...catch block is outside of the promise initialization code, and once it initializes the promise, it's done. So the try...catch block is only handling promise initialization in the code above. If the promise is rejected/errored (as you say it is doing in your code), the error function will fire within the error function closure only.
Consider a common error handler or you can refactor your try...catch block to be within the closure.
Here's the code with the common error handler:
try {
myPromise().then(function(){
console.log("ok");
}, function(err) {
errHandler(err);
});
} catch(e) {
errHandler(e);
}
function errHandler(err) {
console.log("error");
}
You have two options:
1) Use Promise.catch:
myPromise().then(function(){
console.log("ok");
}, function(err) { throw err; })
.catch(function(err) { console.log("error"); });
2) If you have transpiler use async/await:
async function parentFunction() {
try {
await myPromise();
console.log("ok");
}
catch (e) {
console.log("error");
}
}

Error : Callback was already called when using pg-promise with async series

I'm having trouble understanding the output printed why executing this code :
1
2
Unhandled rejection Error: Callback was already called.
It seems like both then and catch are executed when the query is successful.
Any idea ?
Cheers
async.series([
function(callback) {
db.none(query)
.then(function () {
return callback(null, true);
})
.catch(function (err) {
return callback(err, null);
});
},
function(callback) {
db.any(query)
.then(function (data) {
console.log('1')
return callback(null, data);
})
.catch(function (err) {
console.log('2')
console.log(err);
return callback(err, null);
});
}
],
function(err, results) {
if (results && !results[1].isEmpty()) {
// do something
}
});
EDIT :
TypeError: results[1].isEmpty is not a function
It seems like the problem come from the rest of the code and was just a simple undefined function error, thanks.
But i still don't understand something : why is this error catched inside the second query instead of outside the async queries ?
I'm the author of pg-promise.
You should never use async library with pg-promise, it goes against the concept of shared/reusable connections.
Implementation with proper use of the same connection, via a task:
db.task(t => {
return t.batch([
t.none(query1),
t.any(query2)
]);
})
.then(data => {
// data[0] = null - result of the first query
// data[1] = [rows...] - result of the second query
callback(null, data); // this will work, but ill-advised
})
.catch(error => {
callback(error, null); // this will work, but ill-advised
});
See also: Chaining Queries.
However, in your case it looks like when you call the successful callback(null, data), it throws an error, which in turn results in it being caught in the following .catch section. To test this, you can change your promise handler like this:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
});
It should normally throw an error about Promise missing .catch because you threw an error while in .then and there is no corresponding .catch chained below, which you can also check through this code:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
})
.catch(error => {
// if we are here, it means our callback(null, data) threw an error
});
P.S. You really should learn to use promises properly, and avoid any callbacks altogether. I only provided an example consistent with your own, but in general, converting promises into callbacks is a very bad coding technique.
This is what happens:
callback(null, data) is called within the context of the .then();
async notices that this was the last item of the series, so it calls the final handler (still within the context of the .then());
the final handler throws an error;
because the code runs in the context of .then(), the promise implementation catches the error and calls the .catch();
this calls the callback again;
PoC:
const async = require('async');
async.series([
callback => {
Promise.resolve().then(() => {
callback(null);
}).catch(e => {
callback(e);
});
}
], err => {
throw Error();
})
Have you try to define your function externally:
function onYourFunction() {
console.log('Hi function');
}
and than do:
.then(onYourFunction) //-->(onYourFunction without parentheses )
Unfortunately i don't use pg-promise but i can advise promise
at this point i create all promises that are necessary:
function createPromise(currObj) {
return new Promise(function (resolve, reject) {
currObj.save(function (errSaving, savedObj) {
if(errSaving){
console.log("reject!");
return reject(errSaving, response);
}
console.log('currObj:' + currObj);
return resolve(savedObj);
});
});
}
and then in cascades:
var allPromiseOs = Promise.all(promise1, promise2, promise3);

Calling another prototype method after promise completed

I have following code in my node.js file;
GameHelperAuth.prototype.GetUserViaApi = Promise.method(function (authCookie, callback) {
// get user from API
});
GameHelperAuth.prototype.GetObjectFromCache = Promise.method(function (authCookie, callback) {
// get user from Cache
});
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
// check cache
this.GetObjectFromCache()
.then(function (result) {
if (result) {
return callback(null, result);
}
else {
// not found in cache, get it from API
// **NOT WORKING HERE - undefined error**
this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
I would like to access my instance method from another instance method once promise is completed. But it looks like it loses it's context and cannot find function anymore. (Please see where I am calling GetUserViaApi method)
Is there any way for me to reach that method without creating new instance of my class?
As far as I can see, the simplest fix here is to just declare var self = this in the first line of .GetUser() and then use self instead of this inside the .then callback.
Alternatively if you're using Node 4+ with ES6 compatibility, use an "arrow function" as the outer .then callback that inherits the lexical this instead of contextual this:
return this.GetObjectFromCache()
.then((result) => {
if (result) {
return callback(null, result);
} else {
// not found in cache, get it from API
return this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
NB: note the addition of the return in the first line and in the else clause, necessary to ensure that the function and that branch both correctly return a promise.
FWIW, I also think you can refactor this substantially by eliminating the repeated call to return callback(...) through a chaining .then:
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
return this.GetObjectFromCache()
.then(result => result || this.GetUserViaApi(authCookie))
.then(result => callback(null, result));
}
I've removed both .catch blocks - doing .catch(function(err) { throw err }) is a no-op - AIUI the throw would make the caller end up in their own .catch block so you might just as well let the entire promise reject anyway.

How can I avoid my Q promise catch block being called twice in a NodeJS callback-style API when running mocha unit tests?

We're using the Q promise library in our node API, but allow functions to be called via callbacks.
For example:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}).catch(function (err) {
return cb(err, null);
});
}
When I run my mocha unit tests, if there is an exception in the callback, it results in the the callback being called twice.
For example:
var called = 0;
foo(function (err, res) {
called++;
console.log('err: ' + err);
console.log('res: ' + res);
console.log('called: ' + called);
throw Error(throw Error from foo!');
});
This gives the following result:
err: null
res: true
called: 1
err: Error: throw Error from foo!
res: null
called: 2
One approach we found was to do the following:
function foo2(cb) {
var _result, _err;
Q.fcall(function () {
return true;
}).then(function (result) {
_result = result;
}).catch(function (err) {
_err = err;
}).finally(function () {
_.defer(cb, _err, _result);
});
}
The idea was to have one place where the callback would be called and try to prevent developer errors by enforcing the defer to clear the call stack.
With this approach, our callback is called once, and any errors (or in our case, asserts) get handled directly by the caller.
Is there a better technique we can use? I feel like this is a pretty common scenario, so I'd imagine there exists a cleaner solution...
Modify your foo function to handle both the fulfillment and the rejection in the same then call using 2 separate handlers:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}, function (err) {
return cb(err, null);
});
}

Categories