JavaScript/NodeJs Exception Handling - javascript

I'm confused how to properly catch JavaScript exceptions. I have a background as a Java Dev, so much of what I know about error handling comes from it.
I'm using sequelize for persistence, so messing around with it, I found an example on the web:
try {
//do sequelize stuff
} catch (error){
switch (error.name) {
case 'SequelizeUniqueConstraintError':
//do something
break;
case 'SequelizeValidationError':
//do something else
break;
default:
//do panic stuff
}
}
Well... that encouraged me to take a look inside sequelizer's source code...
What is thrown, is basically that:
class UniqueConstraintError extends ValidationError {
constructor(options) {
options = options || {};
options.parent = options.parent || { sql: '' };
options.message = options.message || options.parent.message || 'Validation Error';
options.errors = options.errors || {};
super(options.message, options.errors);
this.name = 'SequelizeUniqueConstraintError';
this.errors = options.errors;
this.fields = options.fields;
this.parent = options.parent;
this.original = options.parent;
this.sql = options.parent.sql;
}
}
hmmm... Interesting.... why would an exception have a name, besides already having a type?
So I changed my code to deal with the types themselves instead of the names, and it ended up like this:
try {
//do sequelize stuff
} catch (error){
if (error instanceof UniqueConstraintError) {
//do something
} else if (error instanceof ValidationError) {
//do something else
} else {
//do panic stuff
}
}
Needless to say, both work just fine.
Is there something I'm missing here? Am I following the wrong tutorials?
Witch solution would be the 'par excellence' in order to deal with multiple possible exceptions being thrown in modern JavaScript?? (witch may be not necessarily any of the two I've presented here)
Thanks.

Why would an exception have a name, besides already having a type?
For the same reason as using error codes: they serialise well and don't require a reference to the class. Also in some rare occasions (that should be avoided) you might end up with multiple copies of the library being loaded, which define multiple distinct classes with the same name. Checking the .name string still works, using instanceof only works if you reference the same class.
Which solution would be the 'par excellence' in order to deal with multiple possible exceptions being thrown in modern JavaScript?
If instanceof works for you, there's nothing wrong with using it - it's perfectly idiomatic. It's just that some programmers prefer a more defensive style that's more resilient in the face of bugs. Using string constants has its own set of problems, e.g. being prone to misspelling and API incompatibility.

Checking the value of a name property may be considered safer and/or simpler because:
for example, an instance of UniqueConstraintError is also an instance of ValidationError because the former extends the latter, so the order of the instanceof checks is crucial, and easy to get wrong.
for example, instanceof UniqueConstraintError may return false if the instance originated from a different execution context with its own global scope, such as that of an iframe.
If you are happy that neither of these reasons is pertinent then instanceof is more idiomatic and the better choice in my opinion.

Related

How to optimize a parameter validation in Javascript

I have one very interesting question.
We know that we should check every parameter in a function.
So we want to check : if param exists, if type is correct, if it is contain some property in case of JSON type etc. and it should be done in every function.
actually how we can optimize and and avoid a tons of conditional if-else?
I tried to do something like that, but I don't know if it's good. Because it just throws an error and stops a program. But I don't know how it can be done better. I thought that es7 decorators will help me but it isn't because I can't use it for the properties checking because it works only with classes and methods.
export function isExists(param) {
if (param) {
return true;
}
throw new TypeError("Param should exists. Please check it.");
}
export function isJsonObject(itemToTest) {
if (itemToTest) {
return ~Object.prototype.toString.call(itemToTest).search(/Object/);
}
throw new TypeError("itemToTest should exists if you want to test it. Please check it.");
}
export function isOwnPropertyExist(objToTest, propName) {
isExists(objToTest); // Here i want to continue a program workflow or it will be broken if my checking won't have success
isExists(prop);
isJsonObject(objToTest);
if (objToTest.hasOwnProperty(propName)) {
return true;
}
throw new TypeError("objToTest should exists and contains a property with name ");
}
Thanks for any help! This question is tormenting me a more than 2 years.
P.S. I don't want to use Typescript (I just want to know, how do you resolve this moment)

Combine Array with Error in a single type

I have a promise-based library (for Node.js 0.10 - 6.x) with a method that rejects with an Array.
When using Bluebird it results in a warning: a promise was rejected with a non-error.
Wrapping the array into a custom error type is easy, but I want to avoid breaking the library's backward compatibility.
Is it possible to implement such an object that could be used as an array, while being seen by Bluebird as an Error object at the same time?
extras
When inheriting from Error I use the following helper for compatibility with Node.js 0.10 - 0.12:
function inherits(child, parent) {
child.prototype.__proto__ = parent.prototype;
}
And looking at the Bluebird source, maybe there is a way to circumvent its verification somehow:
Promise.prototype._rejectCallback =
function(reason, synchronous, ignoreNonErrorWarnings) {
var trace = util.ensureErrorObject(reason);
var hasStack = trace === reason;
if (!hasStack && !ignoreNonErrorWarnings && debug.warnings()) {
var message = "a promise was rejected with a non-error: " +
util.classString(reason);
this._warn(message, true);
}
this._attachExtraTrace(trace, synchronous ? hasStack : false);
this._reject(reason);
};
Javascript don't permits real multiple prototypal inheritance.
You can "extend" Error but the subclass can't be both instanceof an Error and an Array.
If Bluebird use duck-typing you can try to subclass Array object and simulate Error behavior (interface and and properties), but this depends strongly of Bluebird error-check implementation.
I think is better and robust to wrap the array value into an Error property/attribute.
So long as your environment allows subclassing Error, yes!
I asked about something similar while extending errors to create my own subtypes, which is essentially what you want to do. In fact, I've done something similar to create HTTP-specific errors that include the response's status code.
Assuming your environment does allow class SubError extends Error (and there is a workaround if not), you simply do:
class ErrorWithData {
constructor(msg, data = []) {
super(msg); // this changes with the workaround
this._data = [].concat(data); // make a copy for safety's sake
}
get data() {
return this._data;
}
}
If you're in an older browser that does not allow you to subclass Error, you can use the shim class from #Mosho's answer and replace extends Error in that example with extends ErrorClass.
NodeJS will allow you to extends Error from v4 and on, with v6 having correct/full support for it. Earlier versions require Mosho's workaround.

How to avoid lots of if-else in javascript (nodejs)

Based on a parameter, function should select a json file out of more 100 json and fire a query to other system.
There will lots of query around in hundreds.
Obviously if else and switch won't be manageable. I took a look for strategy patten in the javascript.
var queryCode = req.param('queryCode');
if(queryCode == 'x'){
//do something
} else if( queryCode == 'y'){
//do something
} else if( queryCode == 'z') {
//do something
}
// do something might become large sometimes...
so I want to replace it something like strategy pattern. Which will be the best design.
Thanks in advance for any suggestion for this problem.
First of all, your concern is really good, if/else chains are evil.
When you have some different behaviors -maybe long, maybe unrelated- and you have to choose one in runtime based on some variable value, there is not sense in creating a great list of if else. That would be hard to maintain, introduces risks, most probably is also mixing responsibilities in the same class, adding new behaviors is dirty (can break old things and implies modify already tested classes, add new different responsibilities to an already working class) and many other reasons.
You was already correct mentioning the Strategy pattern. This will be the one that fits better your problem. You can also take a look at the Command Pattern but the general concept will be the same: encapsulate the different behaviors in separate classes.
Then you can use a Factory to retrieve the correct strategy to use.
In a nutshell, you will have a bunch of strategy classes, all implementing a method, lets say execute
//strategyA.js
function StrategyA(){
}
StrategyA.prototype = {
execute: function() {
//custom behavior here
}
}
module.exports = StrategyA;
//strategyB.js
function StrategyB(){
}
StrategyB.prototype = {
execute: function() {
//custom behavior here
}
}
module.exports = StrategyB;
Then you create the factory class, that create the correct class according to a parameter. The mapping value->class ideally would be on a confing file and then register it to the factory class, but for simplicity you can hardcode it in the same file. Something like this:
//factory.js
var StrategyA = require('./strategyA.js'),
StrategyB = require('./strategyB.js');
var _ = require('underscore');//asuming you have underscore
module.exports = function () {
var serviceDescriptions: [
{ name: 'a', service: StrategyA},
{name: 'b', service: StrategyB}
];
var getStrategy: function (name) {
//asuming you have underscore, otherwise, just iterate the array to look for the proper service
return _.find(this.serviceDescriptions, {name: name}).service;
};
}
With all this, starting is more complex, but specially if you have a lot of different strategies, or have to add more in the future, would be a good investment in the midterm. And your main code will be just something as simple as:
var Factory = require("factory.js");
...
var queryCode = req.param('queryCode');
var strategy = Factory.getStrategy(queryCode);
strategy.execute()
So, no matter how many different behaviors you have, or how long or complex or different they are, your main class will always look the same, simple and easy to follow.

Throwing custom exceptions in Javascript. Which style to use?

Douglas Crockford recommends doing something like this:
throw {
name: "System Error",
message: "Something horrible happened."
};
But you could also do something like this:
function IllegalArgumentException(message) {
this.message = message;
}
throw new IllegalArgumentException("Argument cannot be less than zero");
and then do:
try {
//some code that generates exceptions
} catch(e) {
if(e instanceof IllegalArgumentException) {
//handle this
} else if(e instanceof SomeOtherTypeOfException) {
//handle this
}
}
I guess you could include a type property in Crockford's implementation and then examine that instead of doing an instanceof. Is there any advantage from doing one versus the other?
Update 2022
If your environment supports ES6, you should use inheritance from Error class, as recommended by Mozilla:
class IllegalArgumentException extends Error {
// ...
}
This is also the most upvoted answer in What's a good way to extend Error in JavaScript?.
Pre-ES6 (original answer)
Also pre-ES6 environments provide the Error class as basis for exceptions. It already allows you to define a message, but also provides a useful stack property to track down the context of the exception.
You can create your own exception type by using prototypical inheritance. There are already several stackoverflow discussions (for example: here), how to do this properly. However, I had to dig a little bit until I found the correct and modern approach. Please be aware that the approach that is suggested in the Mozilla documentation (see above) is not liked by the stackoverflow community. After a lot of reading I came out with that approach for inherit from Error.prototype:
function IllegalArgumentException(sMessage) {
this.name = "IllegalArgumentException";
this.message = sMessage;
this.stack = (new Error()).stack;
}
IllegalArgumentException.prototype = Object.create(Error.prototype);
IllegalArgumentException.prototype.constructor = IllegalArgumentException;
I am in favor of the second one since it is more reusable in terms of code purity. To be precise, if I am about to throw the same exception (even the same exception type with a different message) on several places, my code would get messy (immense) with the first approach.

Should I be removing console.log from production code?

I currently have this JS statement everywhere in my code:
window.console && console.log("Foo");
I am wondering if this is costly at all, or has any negative side-effects in production.
Am I free to leave client-side logging in, or should it go?
EDIT: In the end, I suppose the best argument I (and anyone else?) can come up with is that there is a possibly non-negligible amount of extra data transferred between the server and the client by leaving logging messages left in. If production code is to be fully optimized, logging will have to be removed to reduce the size of javascript being sent to the client.
Another way of dealing with this is to 'stub' out the console object when it isn't defined so no errors are thrown in contexts that do not have the console i.e.
if (!window.console) {
var noOp = function(){}; // no-op function
console = {
log: noOp,
warn: noOp,
error: noOp
}
}
you get the idea... there are a lot of functions defined on the various implementations of the console, so you could stub them all or just the ones you use (e.g. if you only ever use console.log and never used console.profile, console.time etc...)
This for me is a better alternative in development than adding conditionals in front of every call, or not using them.
see also: Is it a bad idea to leave "console.log()" calls in your producton JavaScript code?
You should not add development tools to a production page.
To answer the other question: The code cannot have a negative side-effect:
window.console will evaluate to false if console is not defined
console.log("Foo") will print the message to the console when it's defined (provided that the page does not overwrite console.log by a non-function).
UglifyJS2
If you are using this minifier, you can set drop_console option:
Pass true to discard calls to console.* functions
So I would suggest to leave console.log calls as they are for a most trickiest part of the codebase.
If minification is part of your build process, you may use it to strip out debug code, as explained here with Google closure compiler: Exclude debug JavaScript code during minification
if (DEBUG) {
console.log("Won't be logged if compiled with --define='DEBUG=false'")
}
If you compile with advanced optimizations, this code will even be identified as dead and removed entirely
Yes. console.log will throw an exception in browsers that don't have support for it (console object will not be found).
Generally yes, its not a great idea to expose log messages in your production code.
Ideally, you should remove such log messages with a build script before deployment; but many (most) people do not use a build process (including me).
Here's a short snippet of some code I've been using lately to solve this dilemma. It fixes errors caused by an undefined console in old IE, as well as disabling logging if in "development_mode".
// fn to add blank (noOp) function for all console methods
var addConsoleNoOp = function (window) {
var names = ["log", "debug", "info", "warn", "error",
"assert", "dir", "dirxml", "group", "groupEnd", "time",
"timeEnd", "count", "trace", "profile", "profileEnd"],
i, l = names.length,
noOp = function () {};
window.console = {};
for (i = 0; i < l; i = i + 1) {
window.console[names[i]] = noOp;
}
};
// call addConsoleNoOp() if console is undefined or if in production
if (!window.console || !window.development_mode) {
this.addConsoleNoOp(window);
}
I'm pretty sure I took much of the above addConsoleNoOp f'n from another answer on SO, but cannot find right now. I'll add a reference later if I find it.
edit: Not the post I was thinking of, but here's a similar approach: https://github.com/paulmillr/console-polyfill/blob/master/index.js
var AppLogger = (function () {
var debug = false;
var AppLogger = function (isDebug) {
debug = isDebug;
}
AppLogger.conlog = function (data) {
if (window.console && debug) {
console.log(data);
}
}
AppLogger.prototype = {
conlog: function (data) {
if (window.console && debug) {
console.log(data);
}
}
};
return AppLogger;
})();
Usage:
var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');
Don't overcomplicate things! I personally use console.log all the time during development, it's just such a timesaver. For production i just add a single line of code (in the "production profile" in my case) that disable all logs:
window.console.log = () => {};
done ;)
This monkey patches window.console and replace the log function with an empty function, disabling the output.
This is good enough for me in most cases. If you want to go "all the way" and remove console.logs from your code to decrease bundle size, you have to change the way your js is bundled (e.g. drop console.logs with minifier or something)
Also I think you CAN actually make a strong point for leaving them in - even in production. It doesn't change anything for a normal user but can really speed up understanding weird "exotic-browser" problems. It's not like it's backend-logs that may contain critical information. It's all on the frontend anyway, not showing a log message because you are scared to reveal something a user shouldn't know really is only "security by obscurity" and should make you think why this information is even available on the frontend in the first place. Just my opinion.
Yes, its good practice to use console.log for javascript debugging purpose, but it needs to be removed from the production server or if needed can be added on production server with some key points to be taken into consideration:
**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
console.log("Debug Message");
}
Above code block has to be used everywhere for logging in order to first verify whether the console is supported for the current browser and whether debug is enabled or not.
isDebugEnabled has to be set as true or false based on our
environment.
TL;DR
Idea: Logging objects precludes them from being Garbage Collected.
Details
If you pass objects to console.log then these objects are accessible by reference from console of DevTools. You may check it by logging object, mutating it and finding that old messages reflect later changes of the object.
If logs are too long old messages do get deleted in Chrome.
If logs are short then old messages are not removed, if these messages reference objects then these objects are not Garbage Collected.
It's just an idea: I checked points 1 and 2 but not 3.
Solution
If you want to keep logs for sake of client-side troubleshooting or other needs then:
['log', 'warn', 'error'].forEach( (meth) => {
const _meth = window.console[meth].bind(console);
window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
If the workflow is done using the right tools such as parcel/webpack then it's no longer a headache, because with the production build console.log is being dropped. Even few years earlier with Gulp/Grunt it could've been automated as well.
Many of the modern frameworks such as Angular, React, Svelte, Vue.js come with that setup out-of-the-box. Basically, you don't have to do anything, as long as you deploy the correct build, i.e. production one, not development which will still have console.log.
I basically overwrite the console.log function with the one what has knowledge of where the code is being run. Thus i can keep using console.log as I do always. It automatically knows that I am in dev/qa mode or in production. There is also a way to force it.
Here is a working fiddle.
http://jsfiddle.net/bsurela/Zneek/
Here is the snippet as stack overflow is intimated by people posting jsfiddle
log:function(obj)
{
if(window.location.hostname === domainName)
{
if(window.myLogger.force === true)
{
window.myLogger.original.apply(this,arguments);
}
}else {
window.myLogger.original.apply(this,arguments);
}
},
I know this is quite an old question and hasn't had much activity in a while. I just wanted to add my solution that I came up with which seems to work quite well for me.
/**
* Logger For Console Logging
*/
Global.loggingEnabled = true;
Global.logMode = 'all';
Global.log = (mode, string) => {
if(Global.loggingEnabled){
switch(mode){
case 'debug':
if(Global.logMode == 'debug' || Global.logMode == 'all'){
console.log('Debug: '+JSON.stringify(string));
}
break;
case 'error':
if(Global.logMode == 'error' || Global.logMode == 'all'){
console.log('Error: '+JSON.stringify(string));
}
break;
case 'info':
if(Global.logMode == 'info' || Global.logMode == 'all'){
console.log('Info: '+JSON.stringify(string));
}
break;
}
}
}
Then I typically create a function in my scripts like this or you could make it available in a global script:
Something.fail = (message_string, data, error_type, function_name, line_number) => {
try{
if(error_type == undefined){
error_type = 'error';
}
Global.showErrorMessage(message_string, true);
Global.spinner(100, false);
Global.log(error_type, function_name);
Global.log(error_type, 'Line: '+line_number);
Global.log(error_type, 'Error: '+data);
}catch(error){
if(is_global){
Global.spinner(100, false);
Global.log('error', 'Error: '+error);
Global.log('error', 'Undefined Error...');
}else{
console.log('Error:'+error);
console.log('Global Not Loaded!');
}
}
}
And then I just use that instead of console.log like this:
try{
// To Do Somehting
Something.fail('Debug Something', data, 'debug', 'myFunc()', new Error().lineNumber);
}catch(error){
Something.fail('Something Failed', error, 'error', 'myFunc()', new Error().lineNumber);
}

Categories