How to avoid errors when manipulating unknown object/function input - javascript

When handling user input (in a JS library, not form text), it's easy to throw type-related errors, when a user supplies a non-function and you expected a function for instance. Suppose I have a function callFn that takes a function and arguments to supply to it and evaluates the function or returns null if it fails to, I can either use try-catch or simply check that the input is a function before calling:
callFn(fn, args) {
return fn instanceof Function ? fn.apply(window, args) : null;
}
//vs
callFn(fn, args) {
var ret = null;
try {
ret = fn.apply(window, args);
}
catch (e) {
console.error(e) //Still display error for debugging
}
return ret;
}
What are the advantages and disadvantages of both ways? Am I correct in the following:
Try-catch is slower, but not significantly so
Try-catch can prevent optimization (see In Javascript, is it expensive to use try-catch blocks even if an exception is never thrown?, not sure if this still applies, can't find anything more recent)
Try-catch will also handle any errors in the supplied function, which can be advantageous or disadvantageous depending on context
Any the biggest one and why I'm considering switching to try-catch
If the user supplies an object with 10+ fields and many of those fields are functions to evaluate or objects to access, a single try-catch statement will suffice if the function returns the same for any error, but the error preventing way would have to 10 - 20 instanceof/typeof statements; thus try-catch is much more readable (and faster to write).
I'm asking since I hardly ever see try-catch, and was unsure if there is a better (good) reason for it to be bad practice.

Related

Return undefined or throw error upon invalid function input?

I know this is a duplicate but the anwser over here simply does not satisfy me:
JS library best practice: Return undefined or throw error on bad function input?
I'd like to talk about a few things that were pointed out and what remained unclear to me.
First off I'd like to present one example where I personally would rather throw an error then return undefined.
function sum(a, b)
Say the consumer passes a string because he passed the direct value of an input box and the end user typed in something other than a number.
If I as the author of sum had returned undefined upon string input, then even if the dev had typed in a string at some point, nothing would have happened and he wouldnt have cared, as thats what was to be expected. But in this case, had I thrown an error, the dev would have realised that thats actually an edge case that had to be handled, because after all, no one wants errors in their program.
So basicly, why not make devs aware of edge cases by actually throwing errors?
This was a comment on the question mentioned above which pretty much is exactly what I am asking but no one replied yet:
"But since it takes 1 extra min for me to throw an error instead of dying silently, won't that save hours in debugging time for those who didn't take the time to read the docs?"
Another point that is in the accepted anwser from above:
"Catching an exception is a lot slower than testing a return value so if an error is a common occurrence, then exceptions will be a lot slower."
The only case I can think of where this qoute applies to is with I/O or networky stuff where the input is always in the correct format but e.g. a user does not exist with that id.
In cases like that, I understand why throwing an error would slow down the process. But again, what about a math library consisting of only pure, synchronous functions?
Isn't it smarter to check the input instead of checking the output? (Make sure the input will work instead of running the function and checking if undefined is returned)
A lot of my confusion really stems from type checking actually as I do come from the C# world and think a library should be used in its exact way as intended rather than it being merciful and working anyway.
I would argue that for an OO language it's common to return null even though that's bad practice and the inventor of null calls it the billion dollar mistake.
Functional languages have solved this problem before OO even existed by having a Maybe type.
When composing functions you could use a variation of a Maybe that contains a Success or Failure, Scott Wlaschin calls this railway orientated programming and Promises are a kind of railway orientated programming.
The problem with using Maybe in OO is that you don't have union types. In F# your code would look like this:
let x =
// 9/0 throws so divideBy returns None the caller of divideBy can
//decide what to do this this.
match (divideBy 9 0) with
| Some result -> //process result
| None -> //handle this case
When matching something in F# you'll get a compile time error if you forget a case (not handle the None). In OO you won't and are stuck with runtime errors or failing quietly. Improvements in C# may come with the compiler warning you when you try to access nullable types but that only takes care of the if not null, it does not force you to provide an else.
So in JavaScript I would advice using Promises or returning a result object. Promises are native to modern browsers and nodejs. In the browser it will shout at you in the console when you do not handle failed promises (errors in console and break at uncaught rejection in sources). In the future; for nodejs; it will cause your process to stop as with an unhandled exception.
//example with promises
const processNumber = compose([
//assuming divideBy returns a promise that is rejected when dividing by zero
divideBy(9)
,plus(1)
,minus(2)
,toString
])
// 9/0 returns rejected promise so plus,minus and toString are never executed
processNumber(0)
.then(
success => //do something with the success value
,fail => //do something with the failure
);
//example of result type:
const Success = {}
,Failure = {}
,result = (type) => (value) =>
(type === Failure)
//Failure type should throw when trying to get a value out of it
? Object.create({type:type,error:value}, {
value: {
configurable: false,
get: function() {
throw "Cannot get value from Failure type"
}
}
})
: ({
type:type
,value:value
})
;
//convert a function (T->T) to (result T->result T)
const lift = fn => arg => {
//do not call funcion if argument is of type Failure
if(arg.type === Failure){
return arg;
}
try {
const r = fn(arg.value);
//return a success result
return result(Success)(r);
} catch (e) {
//return a failure result
return result(Failure)(e);
}
};
//takes a result and returns a result
const processNumber = compose(
[
//assuming divideBy throws error when dividing by zero
divideBy(9)
,plus(1)
,minus(2)
,toString
].map( //lift (T->T) to (result T -> result T)
x => lift(x)
)
);
const r = processNumber(result(Success)(0));//returns result of type Failure
if(r.type === Failure){
//handle failure
} else {
//handle r.value
}
You could just return null or throw but more and more people in OO start to realize that's not the best way to handle things. Throwing is a side effect so makes the function impure (the more impure functions the harder it is maintain your code).
Null is not good type to reflect functions that could fail. You don't know why it failed to return the expected type and now have to make assumptions as to why, making assumptions in code makes your code harder to maintain.

Node.js: Why should you return the result of a callback during error handling?

Newbie to Node.js here. I'm learning Node.js via the tutorials at NodeSchool.io, and in one tutorial where we learned about modules, we were required to write something like this code:
// Some code...
function filteredLs(dir, ext, callback) {
fs.readdir(dir, function(err, files) {
if (err)
return callback(err); // return statement necessary here...
callback(null, withExtension(files, ext)); // ...but not here
})
}
module.exports = filteredLs;
My question is, in examples like these, why is it necessary to include the return statement when handling the error, but OK to omit when it's null? I don't see what use the return value of the function could have to readdir anyhow, since it happens after it finishes its work. Why does it make a difference?
The use of return when calling a callback function is typically there to prevent the code that follows from running. The returned value is typically irrelevant.
That's why it's needed in the error case, so the callback call for the non-error case isn't also called.
It's not needed in the non-error case because it's already the last line of the function.
The error handling boilerplate you posted is indeed confusing. It uses a maximally-terse way of expressing the code, but is indeed confusing, and you are right that the return value is discarded. Thus my preferred boilerplate for clarity is
if (error) {
callback(error)
return
}
Which I feel is slightly clearer and the reduced concision is not that important to me (I type it with a macro anway).
I find this to make it clearer that there are 2 distinct intentions being expressed here:
Bubble the error back up to the caller
Exit the function as there's nothing else useful to be done. No return value because the callback protocol does not require one and the calling code does not need to and probably will not even capture the return value into a variable.

Uses of the finally statement

This is a very basic question. In Java I use the finally statement to close resources because "it's a good practice". I've been developing in Javascript and then in Node.js during some years and I've never used the finally statement. I know that in Node.js all of us follow the first parameter error handling pattern. Anyway, the 2 following snippets do the same:
try{
throw 123
}catch (e){
}finally{
console.log(1)
}
.
try{
throw 123
}catch (e){
}
console.log(1)
Both print 1.
Why is finally a keyword if it has no real benefit? The clean up code can be put inside the catch.
finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break.
Just a simple and straightforward example that shows the difference. There is a return that breaks the function completion, but the console.log in finally is called while the last console.log is skipped.
let letsTry = () => {
try {
// there is a SyntaxError
eval('alert("Hello world)');
} catch(error) {
console.error(error);
// break the function completion
return;
} finally {
console.log('finally')
}
// This line will never get executed
console.log('after try catch')
}
letsTry();
But try this:
try {
throw "foo"
} catch (e) {
throw "bar"
} finally {
console.log("baz")
}
console.log("quux")
If a second error is thrown from within the catch block, the code after the try...catch block will not run.
The finally block will always run, even if there is an error in the catch block.
Furthermore, the finally block runs even if a return or break statement stops the code in the try or catch block. return statements in the finally block override return statements in the try or catch block.
function foo() {
try {
return "bar";
} finally {
return "baz";
}
}
foo() // "baz"
oracle docs provide a good answer to this. Bottom line: finally gets called always! Even when you catch only one kind of exception (not the global catch), then finally gets called (after which your application probably breaks if there is no other catch)
the finally block is meant for a special purpose.
finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Since it wont effect your business logic,Still it's compiler friendly,In memory aspects.
What if the try-block returns early or throws an exception that you don't handle? You would still want to free the resources you have allocated, right?
EDIT:
The answers to the question seem almost philosphical, there is some 'guessing' and basically 'we believe it should be useful, because it is there, so it should have a use', and 'even Oracle says so'. Or maybe it is there to help the programmer not 'to forget something' or 'accidently exit and not realize it'.
These are almost all valid reasons, but there is also a technical reason.
It helps avoiding code duplication in the cases mentioned, where (a) either the try or one of the catch blocks returns or (b) if within the catch block a second exception is thrown.
In these cases, if some cleanup code or any other code that still needs to be executed after the return and after the second exception, could be placed into the finally block, if it is to be executed both after the try and after the catch block.
You could still do it without the finally block, but the code would have to be duplicated, which the finally block allows you to avoid. This is where you really need it.
So if you are sure you do not miss it as a case of (a) or (b) you could still put the 'finally' code after the try/catch block and omit the finally clause.
But what if the situation changes? When you or another person change the code at some later point it could be forgotten to check if the cleanup code is now skipped in some situation.
So why not always put the cleanup code inside the finally block? And this is what is recommended and what many JavaScript programmers do.
You use it when you want to be sure your code is executed at the end, even if there was an exception during execution :
InputStream is = new FileInputStream("C://test.txt");
try {
//code...
} catch (Exception e) {
//code...
} finally {
is.close();
}
This is a very good question.
There is little to no reason to use finally in javascript, but I can imagine situations where it could be of practical use.
Suppose you have a webpage where you show a certain div after some user action, e.g. button clicked.
The div shows some logging for instance for the action the user requested.
After the action is complete (error or no error), you want to be sure to hide the div again. For that you can use the finally clause.
function doSomething() {
var d = document.getElementById("log");
show(d);
try {
... execute action ...
} catch(e) {
log(e);
} finally {
hide(d);
}
}
In general, as you mentioned, exceptions are less and less used in JavaScript in favor of error callbacks.
So, one could as well ask, what good uses are for exceptions in JavaScript in general.
The problem is with your example. There are cases when you don't want to catch the exception.
try {
if (Math.random() > 0.5) throw 123
}
finally {
console.log(1)
}
In these cases all you could do is rethrowing the exception if you don't want to use finally.
try {
if (Math.random() > 0.5) throw 123
}
catch (e) {
console.log(1)
throw e
}
console.log(1)
or maybe
try {
if (Math.random() > 0.5) throw 123
console.log(1)
}
catch (e) {
console.log(1)
throw e
}
Both alternative solutions lead to code duplication, that's why you need the finally keyword. It is used most of the time to free up unused resources. Forgetting about it may lead to unwanted locks or connections or memory leaks. I guess in some cases even a smart GC cannot prevent it.
In Java, if there's an Exception thrown that is not matched by any of the catch-blocks execution will break and any open resources will be left open.
The finally block will always be executed, even if an uncaught exception occurs.

Javascript error stops code execution

Whenever an error occurs inside an event handler, it stops code execution entirely so the second event callback isn't called.
For example:
$(function() {
window.thisDoesntExist();
}
$(function() {
//Do something unharmful and unrelated to the first event
}
You can easily solve the problem in this (simplified) example by adding try/catch in both anonymous functions, but in reality these functions often add several other event handlers which in turn would require try/catch. I end up with very repetitive code stuffed with try/catch blocks.
My projects has a modular design where each feature is in a different JS (and gets concatenated during a build process). I'm looking for a more generic way to handle errors inside each feature so that the error doesn't stop code execution of the other features.
I already tried following solutions:
- window.onerror (even if you return true in this function, code execution is stopped)
- $(window).error() => deprecated and code execution stops
You could create a helper function to prevent duplication of the same boilerplate code.
function tryFunction(f, onerror) {
try {
if (typeof f == 'function') {
return f();
}
} catch (e) {
return onerror(e);
}
}
$(function() {
var result = tryFunction(window.thisDoesNotExist, function (error) {
alert('Whoops: ' + error);
});
});
I created a little demonstration. It's slightly different but the same idea.
You can simply call if (typeof myFunction == 'function') before calling myFunction()
And optionally wrap it in a generic function like said by Bart to have the choice to log an error in the console if your function does not exists.
If your webapp is huge with many interaction and JS, too many try catch could alter the global performance of your application.
I would try something like this with a wrapper which will handle the try catch for you (see below, or this jsfiddle : http://jsfiddle.net/TVfCj/2/)
From the way I'm (not, and not really) handling the this and the arguments, I guess it's obvious I'm beginning with js. But I hope you get the idea, and it is correct/useful.
var wrapper = {
wrap: function wrap(f) {
return function (args) {
try {
f.apply(null, args);
} catch (ex){
console.log(f.name+" crashed with args "+args);
};
};
}
};
var f1 = function f1Crashes(arg) {
return window.thisDoesntExist();
};
var f2 = function f2Crashes(arg) {
return window.thisDoesntExist();
};
var f3 = function f3MustNotCrash(arg) {
wrapper.wrap(f1)(arg);
wrapper.wrap(f2)(arg);
}
f3('myarg');
The try-catch pattern you mention attempting in your question is the correct way - you want try-catch blocks, not a way to silently truck through module errors (in general always be extremely careful handling exceptions globally and continuing, that way lies data corruption bugs you only find 6 months later).
Your real problem is this:
... in reality these functions often add several other event handlers which in turn would require try/catch. I end up with very repetitive code stuffed with try/catch blocks.
The fix for that is Promise. This is a new structure, native in most browsers but easily shimmed in the slow ones (ahem, IE), that gives you a standard way of managing both the event callback and the exception from the event.
With a Promise your code makes a promise to always do something: either resolve/succeed or reject/fail.
function moduleA() {
return new Promise(function (resolve, reject)
{
try{
var result = window.thisDoesntExist();
resolve(resolve); // Success!
}
catch(err){
reject(err); // Fail!
}
});
}
This is better because rather than nest try-catch blocks in each callback you can instead chain promises:
moduleA().
then(moduleB).
then(moduleC).
catch(errorHandler); // Catch any error from A, B, or C
You can also handle an error and continue:
moduleA().
catch(continuableErrorHandler). // Catch any error from A
then(moduleB).
then(moduleC).
catch(errorHandler); // Catch any error from B or C
You'll still need lots of try-catch blocks in callbacks, but anything that has been wrapped in a Promise can be treated in the same modular way.
Coming next in JS is async and await, but you can use them now with a transpiler. These use promises to make code that is much easier to read, and most importantly (for you) have a single try-catch at the top that gathers exceptions from the entire Promise chain.
This answer is already too long, but I've blogged about that in more detail.
TL;DR: If your problem is "very repetitive [event callback] code stuffed with try/catch blocks" try using Promise instead.
I found a solution. When using setTimeout, the code is executed in a seperate thread, therefor it won't break any other parts of the webpage.
$(function() {
setTimeout(function() {
window.thisDoesntExist();
}, 0);
});
$(function() {
setTimeout(function() {
//Do something unharmful and unrelated to the first event
alert("This passes")
}, 0);
});
In this example, the second function is run, even when the first one throws an error.
Here's a working example: http://jsfiddle.net/mathieumaes/uaEsy/

Using Node.js, is there some semantic to tell me when code is going to leave the current stack?

Right now, it's a mystery to me if my try/catch blocks are going to work at all. I set them around code, and then, because something in the code was "asynchronous", which appears to be a fancy way of saying forked to another thread/process at the OS level, the try/catch is ignored if it happens in that code.
I'm fine with that, I just want to know if there's some indication of this? By convention, I'm given to understand, if a call asks for a callback, it's asych, otherwise it's not. I get why a callback means asych, but I'm afraid that the reverse isn't always true: THere's nothing stopping me from surrounding a call with a try/catch that gets loaded into a new call stack and also doens't ask for a callback. This seems really messy to me, and I'd like a little more control over my try/catches than using the default callback that all uncaught exceptions are handled by, if possible.
Is there a semantic to tell me when code is going to leave the
current stack?
UPDATE: here is an example:
var UserSchema = new mongoose.Schema({
email: {type: String, unique: true},
password: String,
firstName: String,
lastName: String,
created_at: {type: Date, default: Date.now},
updated_at: Date
});
var User = mongoose.model('User', UserSchema);
var users = [
{email: 'foo#bar.com', firstName: 'Justin', lastName: 'Jones'},
{email: 'foo#bar.com', firstName: 'Justin', lastName: 'Jones'}
];
users.forEach(function(user) {
var newUser = new User(user);
newUser.save(function(err, obj) {
if (!err) console.log("Saved: ", obj.email);
});
});
Given the code above, there's no way to catch an exception inside of save(), as it happens in another call stack. Is there any way for me to externally know that's what's about to happen when I call save()?
UPDATE: Everyone telling me to use handlers for this should maybe read this? It's clearly suggesting not to deal with exceptions that aren't caught in their "thread execution", quotes since it only acts like a thread.
"Asynchronous" is not "a fancy way of saying forked to another thread/process".
JavaScript is single-threaded. End of story. There is no forking at the language level.
"Asynchronous" means just what it says: The order of execution is not the order of the code. Some bits of the code - callback functions - will execute at some point in time, when a certain event occurs. It is an event-based programming model.
Consider this simple example:
function hello () { alert("Hello!"); }
setTimeout(hello, 2000);
This is an asynchronous callback in its most basic form. You have a callback handler - the function hello - and an event generator, in this instance a time-based one.
Once the event occurs (2s have have passed), the callback handler is called.
Now for a modification:
function hello() { alert(foo.bar); }
try {
setTimeout(hello, 2000);
} catch (ex) {
alert(ex.message);
}
We introduce a try-catch block around setTimeout. It guards the registration of a callback, nothing more. Most likely this step will succeed, hence the try-catch block will never do anything. The fact that the callback itself will fail in 2 seconds from now does not affect the try-catch block, naturally. This is the behavior you find confusing.
Now for another modification:
function hello() {
try {
alert(foo.bar);
} catch (ex) {
alert("foo.bar is not defined");
}
}
setTimeout(hello, 2000);
Now the try-catch block guards the step that can actually fail. This implies that you must use try-catch blocks where the errors can occur, not generally wrap them around large sections of your program (which is what you seem to do).
But how to get the exception to do do something useful and configuable? By introducing more callbacks, naturally.
function hello(onError) {
try {
alert(foo.bar);
} catch (ex) {
onError("foo.bar is not defined", ex);
}
}
function errorHandler(customMessage, exception) {
alert(customMessage);
// or do something with exception
}
setTimeout(function () {
hello(errorHandler)
}, 2000);
As per your added example:
var saveUsers = function(users, onSuccess, onError) {
users.forEach(function(user) {
var newUser = new User(user);
newUser.save(function(err, obj) {
if (err) {
onError(err, obj);
return false;
} else {
onSuccess(obj);
}
});
});
}
var users = [
{email: 'foo#bar.com', firstName: 'Justin', lastName: 'J'},
{email: 'foo#bar.com', firstName: 'Justin', lastName: 'J'}
];
saveUsers(
users,
function (user) { console.log("Saved: ", user.email); },
function (err, user) { console.log("Could not save: ", user.email); }
});
The semantic is literally just when the function you called has finished executing. If it spawns an I/O process and registers an event, your try-catch block won't surround that because it's executed on another loop through the implicit Javascript event loop.
The presence or nonexistence of a callback parameter in the function you're executing has no bearing whatsoever on whether or not work started by the function will cause an event to fire off somewhere else. An EventEmitter-based object registers handlers with the .on('eventName', functionName) mechanism, so multiple events and multiple handlers can be accessing the same "work" but that is all kicked off by a function that takes no callbacks. While the Array object's forEach method takes a callback and is synchronous.
Simply put, nothing beyond the event loop barrier should cause a Javascript exception to be thrown. Only the code on the Javascript side of things can. So you put your try-catch blocks, if needed, on that side: In your function that calls the possibly async code if that function will possibly throw an error, and in your callback function itself if it calls something that could possibly throw an error. If it's async, they are two separate call stacks from Javascript's perspective, so they have different try-catch scopes; if it's sync, you'll just have one extra set of try-catch checks, and at least you'll have a better idea of what could have thrown the error.
Personally, I think try-catch just doesn't work in a language like Javascript, and was added to make it more Java-like, so I try to avoid code that uses throw for Node.js stuff. (Exceptions are if it's using them only for initial configuration of the library/object that can't work or if it's using it [poorly, in my opinion, because of the execution overhead] as an internal way to break out of deep synchronous code and doesn't expose it to me.)
EDIT: To better explain the callstack in Javascript, here's a simple ASCII diagram showing each level of the stack versus time:
== Javascript Event Loop =========================================================
== My Awesome Function ====================================== == My callback ==
== Call to an async library ====================
== I/O request and callback registration ===
Anything that is thrown by My callback will be sent straight back to the Javascript Event Loop and can only be caught by registering a process.on('uncaughtException', myFunc) handler to take care of it at that point. Basically, any code of your own can certainly use try-catch, but it should never throw if it'll be called directly as an event handler.
As for your recent edit to your question async.forEach will solve your issue. You pass it the array to iterate over, then the function to execute on each item in the array, and then a "finally"-style function to either handle an error or continue your code from there.
Nathan: I'm not going to go into the bigger question of finding out "when code is going to leave the current stack". I can help you with saving your users though. I recommend the great async library:
function saveUser(user, callback) {
new User(user).save(callback);
}
async.forEach(users, saveUser, function(err, results) {
// Respond
});
If you're simply using callback functions, then it doesn't matter. NodeJS is single-threaded, thus everything is on the same call stack.
BUT! You're right about NodeJS may sometimes "leave" the current call stack. The leave is in quote because it's not really leaving the current call stack but simply returning to the root call (process.nextTick()). Then on the next tick, it's spawn a "new" call stack.
If you want a semantic, I guess you can say that anywhere that you're using EventEmitter, you're passing that callback function to the next tick and therefore "moving" it to another call stack. (But even so, it's not entirely true, because EventEmitter actually dispatches event on the current tick).

Categories

Resources