Javascript Error Handling example - javascript

I have two functions one which checks the value of id and makes sure its 0 or greater else throws an error.
function getPerson(id) {
if (id < 0) {
throw new Error('ID must not be negative '+id);
}
return {id:id};
}
function getPersons(ids) {
var result = [];
ids.forEach(function (id) {
try {
var person = getPerson(id);
result.push(person);
} catch (err) {
console.log(err);
}
});
return result;
}
getPersons([2, -5, 137]);
Now I am reading a book called Speaking Javascript by Dr.Axel Rauschmayer
and this is an example from the book. I am curious as to why the error being thrown isn't being caught.
My desired result would be for it to log the error but keep running and return the result array.

You are seeing the error object being logged, but instead of logging just the error object, log the error's message and you will see that the error is, in fact, being thrown as you designed it.
function getPerson(id) {
if (id < 0) {
throw new Error('ID must not be negative '+id);
}
return {id:id};
}
function getPersons(ids) {
var result = [];
ids.forEach(function (id) {
try {
var person = getPerson(id);
result.push(person);
} catch (err) {
console.log(err.message);
}
});
return result;
}
getPersons([2, -5, 137]);
NOTES:
I realize you are working your way through an exercise here but
understand that throwing and catching errors is something that should
be done as a last resort and only in situations where an exception
could be thrown through no fault of your own (i.e. network and
server-side failures). This is because throwing exceptions and catch
blocks have performance implications. When something doesn't meet
your criteria, return a special value that indicates that and check
for that value in other places.
Even when try/catch is warranted, it is a best-practice to never
place them inside of a loop (again for performance reasons). If you
loop goes 10,000 times and you encounter numerous errors, each one of
them will be caught and handled, dramatically affecting performance.
Instead place the loop inside of the try section and, upon the
first error, the code will proceed to the catch.

You need to use the attribute message from object Error.
function getPerson(id) {
if (id < 0) throw new Error('ID must not be negative ' + id);
return {id};
}
function getPersons(ids) {
var result = [];
ids.forEach(function(id) {
try {
var person = getPerson(id);
result.push(person);
} catch (err) {
console.log(err.message);
}
});
return result;
}
getPersons([2, -5, 137]);

Related

How to satisfy the "consistent-return" rule in eslint using an if-error-return pattern?

I have some code:
foo((error, data) => {
if (error) {
return;
}
// do something with data
});
This will cause a "consistent-return" error to be returned. I understand that this is an opinionated matter, however, what would be a reasonable way to satiate this rule?
Is my approach even correct? Should I be using return to effectively "break" within the callback body? Would I have to add an empty return statement after the // do something with data lines had been executed?
Consistent-return indicates that your function should always return the same type of data. So if you're returning undefined in a error case, you also should return undefined in the other cases.
foo((error, data) => {
if (error) {
return;
}
return;
});
If your function is supposed to return data when error is false, maybe your don't want to return undefined, and throw an Error instead.
foo((error, data) => {
if (error) {
throw new Error()
}
return data; // or anything else
});

How to throw an error without throw

So recently I was asked a question :
Is there a way to throw an error without using throw in javaScript ?
As far as I knew about errors, there was only one way to throw an error in JavaScript and that was using throw statement in JavaScript like so :
var myFunc = () => {
// some code here
throw 'Some error' // in a conditional
// some more code
}
try {
myFunc()
}catch(e) {
console.log(e)
}
And not knowing any other way I said No, there is no other way. But now I'm wondering whether I was right ?
So the question is whether or not you can throw a custom error in JavaScript without using throw
Restrictions :
Kindly no using eval , Function.
Don't use throw in your code
Additional :
If you can throw an error without using the word Error
Generators do have a throw method that is usually used to throw an exception into the generator function code (at the place of a yield expression, similar to next), but if not caught it bubbles out of the call:
(function*(){})().throw(new Error("example"))
Of course, this is a hack and not good style, I have no idea what answer they expected. Especially the "no division by zero" requirement is sketchy, since division by zero does not throw exceptions in JS anyway.
If all you want to do is throw an error then just do an invalid operation. I've listed a few below. Run them on your browser console to see the errors (tested on chrome and firefox).
var myFunc = () => {
encodeURI('\uD800'); // URIError
a = l; // ReferenceError
null.f() // TypeError
}
try {
myFunc()
}catch(e) {
console.log(e);
}
function throwErrorWithoutThrow(msg) {
// get sample error
try {
NaN();
} catch (typeError) {
// aquire reference to Error
let E = typeError.__proto__.__proto__.constructor;
// prepare custom Error
let error = E(msg);
// throw custom Error
return Promise.reject(error);
}
}
throwErrorWithoutThrow("hi")
/* catch the error, you have to use .catch as this is a promise
that's the only drawback, you can't use try-catch to catch these errors */
.catch((e) => {
console.log("Caught You!");
console.error(e);
});
I think, if you want to use try...catch blocks, you will need to throw something to get to the catchpart. You can use pretty much everything that fails with an error to do that (like mentioned in the other posts).
If at some point, you want to run-or-die without having to write the throw statement yourself, you can always do an assertion:
const myFunction = () => {
try {
assert.fail();
console.log(`Did not work :)`);
} catch (e) {
console.log(`OK`);
}
};
Of course I would rather try to assert something positive (more Zen), that I need in order to continue.
const myTypeErr = () => `This is a Custom Err Message... \nand it`()
try {
myTypeErr()
} catch(e) {} // caught
myTypeErr() // Uncaught TypeError: "This is a Custom Err Message...
// and it" is not a function

How to promisify this Mongoose code?

I am trying to use Mongoose's built in promise support to write some clean Javascript code for a user sending a friend request to another. However, when I try to ensure proper error handling and sequentiality, I still end up with a (slightly smaller than normal) pyramid of doom.
Here, I first ensure that the friend request is valid, then save the target's Id to the requester's sent requests then, if that save was successful, save the requester's Id to the target's friend requests.
Do I need to use a third party library like q in order to do this as cleanly as possible? How can I structure this such that I can use the traditional single error handler at the end?
function _addFriend (requesterId, targetId) {
// (integer, integer)
User.findById(requesterId)
.exec((requester) => {
if (!(targetId in requester.friends
|| targetId in requester.sentfriendRequests
|| targetId in requester.friendRequests)) {
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId])
requester.save()
.then((err) => {
if (err) throw err;
User.findById(targetId)
.exec((err, target) => {
if (err) throw err;
target.friendRequests = target.friendRequests.concat([requesterId])
target.save().then(err => {if (err) throw err})
})
})
}
})
}
You will need some nesting to do conditionals in promise code, but not as much as with callback-based code.
You seem to have messed up a bit of the if (err) throw err; stuff, you should never need that with promises. Just always use .then(result => {…}), and don't pass callbacks to exec any more.
If you always properly return promises from your asynchronous functions (including then callbacks for chaining), you can add the single error handler in the end.
function _addFriend (requesterId, targetId) {
// (integer, integer)
return User.findById(requesterId).exec().then(requester => {
if (targetId in requester.friends
|| targetId in requester.sentfriendRequests
|| targetId in requester.friendRequests) {
return;
}
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId])
return requester.save().then(() => {
return User.findById(targetId).exec()
}).then(target => {
target.friendRequests = target.friendRequests.concat([requesterId])
return target.save()
});
});
}
_addFriend(…).catch(err => {
…
})
In English, the way to do this is to use the promises returned by exec() have then blocks return promises, un-indent, then add then to those. Much easier to say in code...
EDIT thanks (again) to #Bergi for making me read and understand the app logic. #Bergi is right that there must be a little nesting to get the job done, but the real point isn't about reducing nesting, but about improving clarity.
Better clarity can come from factoring into logical parts, including some that return in promises.
These few functions conceal the promise nesting that's required by the logic. This doesn't specify (because the OP doesn't indicate how the app should handle) what addFriend should return when it refuses to do so due to an existing request...
function _addFriend (requesterId, targetId) {
// note - pass no params to exec(), use it's returned promise
return User.findById(requesterId).exec().then((requester) => {
return canAddFriend(requester, targetId) ? addFriend(requester, targetId) : null;
});
}
function canAddFriend(requester, targetId) {
return requester && targetId &&
!(targetId in requester.friends
|| targetId in requester.sentfriendRequests
|| targetId in requester.friendRequests);
}
function addFriend(requester, targetId) {
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId]);
return requester.save().then(() => {
return User.findById(targetId).exec();
}).then((target) => {
target.friendRequests = target.friendRequests.concat([requesterId]);
return target.save();
});
}
Once you realise that .exec() returns a promise, you can :
achieve the desired flattening and make the code more readable.
avoid the need to handle errors amongst the "success" code.
handle errors in a terminal .then() or .catch().
As a bonus you can also (more readily) throw meaningful errors for each of those x in y conditions.
Straightforwardly, you could write :
function _addFriend(requesterId, targetId) {
return User.findById(requesterId).exec().then(requester => {
if (targetId in requester.friends) {
throw new Error('target is already a friend');
}
if (targetId in requester.sentfriendRequests) {
throw new Error('friend request already sent to target');
}
if (targetId in requester.friendRequests) {
throw new Error('target already sent a friend request to requester');
}
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId]); // or just .push()?
return requester.save();
}).then(() => {
return User.findById(targetId).exec().then(target => {
target.friendRequests = target.friendRequests.concat([requesterId]); // or just .push()?
return target.save();
});
});
}
Note the need for returns to control flow.
But you could do even better. As writtten above, the requested stuff could succeed then the target stuff fail, resulting in a db disparity. So what you really want is a db transaction to guarantee that both happen or neither. Mongoose undoubtedly provides for transactions however you can do something client-side to give you something transaction-like with partial benefit.
function _addFriend(requesterId, targetId) {
return Promise.all([User.findById(requesterId).exec(), User.findById(targetId).exec()]).then(([requester, target]) => { // note destructuring
if (targetId in requester.friends) {
throw new Error('target is already a friend');
}
if (targetId in requester.sentfriendRequests) {
throw new Error('friend request already sent to target');
}
if (targetId in requester.friendRequests) {
throw new Error('target already sent a friend request to requester');
}
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId]);
target.friendRequests = target.friendRequests.concat([requesterId]);
return requester.save().then(() => {
return target.save();
});
});
}
Here, you could still get the (unlikely) situation that the first save is successful and the second save fails, but at least you have the assurance that absolutely nothing happens unless both the requester and target exist.
In both cases, call as follows :
_addFriend(requesterId, targetId).then(function() {
// do whatever on success
}, function(error) {
// do whatever on error
});
Even if you don't use the error messages in the live environment, they could be very useful when testing/debugging. Please check them - I may have gotten them wrong.

understanding exception handling in JavaScript: get different output when changed the place of try/catch block

I am new to learning JavaScript and sort of stuck up while learning exception handling.
I have understood the thing that whenever an exception occurs , it is thrown using "throw" keyword and similarly it is caught using "catch" block.
But what I am unable to understand is that , I have a small , simple code that demonstrates simple Exception handling technique, and in that code whenever I change the place of the catch block, I get different outputs. Here is the simple code and its different o/p s depending upon where I place the catch block.
function lastElement(array) {
if (array.length > 0)
return array[array.length - 1];
else
throw "Can not take the last element of an empty array.";
}
function lastElementPlusTen(array) {
return lastElement(array) + 10;
}
try {
print(lastElementPlusTen([]));
}
catch (error) {
print("Something went wrong: ", error);
}
the o/p that I get here is as expected :
Something went wrong: Can not take the last element of an empty array.
now when I add the try/catch block around the function lastElementPlusTen: like this
function lastElement(array) {
if (array.length > 0)
return array[array.length - 1];
else
throw "Can not take the last element of an empty array.";
}
try {
function lastElementPlusTen(array) {
return lastElement(array) + 10;
}
}
catch (error) {
print("Something went wrong: ", error);
}
print(lastElementPlusTen([]));
now the o/p that I get here is :
Exception: "Can not take the last element of an empty array."
the "something went wrong" from the catch block is not printed.
why is this so??similarly when I place the try/catch block around different pieces of code
(for ex: around the first function , body of the lastElementPlusTen function etc) I get different o/p s. why is this happening. How does exception handling work??
The problem is that you're putting the try/catch around the function declaration -- the error is not thrown there, it's thrown when the function is actually invoked. So you need this instead:
// this code block will not throw any error, although it will when the function is invoked
function lastElementPlusTen(array) {
return lastElement(array) + 10;
}
try{
console.log(lastElementPlusTen([]));
}
catch (error) {
console.log("Something went wrong: ", error);
}
Fiddle demo
You are not catching the exception in your second case. It just throws the exception unhandled not printing it as you expect, place
print(lastElementPlusTen([]));
inside try..catch
Try:
function lastElement(array) {
if (array.length > 0) return array[array.length - 1];
else throw "Can not take the last element of an empty array.";
}
function lastElementPlusTen(array) {
return lastElement(array) + 10;
}
try { //<-- this is where you need try.. catch not at the function definision
print(lastElementPlusTen([])); //<-- this invokes the error.
} catch (error) {
print("Something went wrong: ", error);
}
Demo Watch the console for the log

continue execution after a throw in JS

i have this function in my code and I'm using throw to create meaningful errors (rather than failing silently). However, when i structure my function this way, if i call defineSandbox() with an error, it stops the whole script.
//defineSandbox is in an object, for now i name "myObj"
var defineSandbox = function (sandboxName,SandboxDefinition) {
//validation
if(!is.validString(sandboxName)) {
throw statusMessages.sandbox.invalidName;
}
if(!is.validFunction (SandboxDefinition)) {
throw statusMessages.sandbox.invalidDefinition;
}
//...some more validation here
//...sandbox builder code if validation passes (code wasn't returned)
registered.sandboxes[sandboxName] = newSandbox;
};
//intentional error, non-string name
myObj.defineSandbox(false);
//...and so the rest of the script from here down is not executed
//i can't build this sandbox anymore
myObj.defineSandbox('mySandbox',function(){...});
what i would like to have is if one call fails, it gives out an error but still tries to continue to run the script. how do i structure this code so that i can achieve that?
Typically, you don't want to continue execution when you manually throw a new error. If you want to have it for a logging purpose, you should consider an self-created internal solution.
However, to catch a thrown error you need to invoke a try / catch statement.
try {
myObj.defineSandbox(false);
} catch( ex ) {
// execution continues here when an error was thrown. You can also inspect the `ex`ception object
}
By the way, you can also specify which kind of error you want to throw, for instance a type error or a reference error like
throw new TypeError();
throw new ReferenceError();
throw new SyntaxError();
etc.
Complete list: MDN
console.error() will not throw an error, but will display an error in your log without halting execution.
If you would like to report the caught error so that window.onerror will fire, you can dispatch an error event in your catch block:
try {
}
catch (error)
{
const e = new ErrorEvent('error', {message:'my error', error:error})
window.dispatchEvent(e)
}
I found this useful for catching and reporting errors in a for loop while still continuing with the loop.
If you are trying to aggregate all the errors instead of just throwing one of them, then you should create an array of the issues (exceptions) and then throw the array, instead of just the first issue you hit.
You need to catch thrown errors if you want to deal with them nicely. In your example:
//intentional error, non-string name
try {
myObj.defineSandbox(false);
} catch(error) {
alert("Error defining sandbox: " + error);
}
And then subsequent code will still continue to run.
var bear = {};
(function () {
bear.errorProcesser = function ( e ) {
console.log( e );
}
bear.define = function ( name, fn ) {
try {
if( typeof name != "string" || typeof fn != "function"){
throw new Error ("some error");
}
bear[name] = fn;
} catch (e){
bear.errorProcesser ( e );
}
}
})()
bear.define ( "testfunc", {} );
Is it just try-catch you're searching for?

Categories