Is try-catch faster than fail only if-else? - javascript

My situation is I have a small javascript program running on a huge amount of data formatted as a 2 dimensions array. For every cycle, it loops through the data, calls a serializer method to serialize that record before doing the calculations. The data for every cycle will be the same. So now I want to cache the serialized data into another array so that from the second time it doesn't have to call serializer again.
Here is my function:
var cached=[];
function getRow(x,y){
if(!cached[x]){
cached[x] = [];
}
if(!cached[x][y]){
cached[x][y] = serializer(data,x,y);
}
return cached[x][y] ;
}
So far it works. But as you can see, for every row it must check 2 conditions before returning cached data and the condition only helpful in the first cycle. So I'm thinking about using try-catch instead of if-else to handle it. So that in the first cycle, the try block will fail all the time then I will fill up the cache in catch block. Then after the first cycle when all the data has been cached, it will just get the value right the way and return it.
But my concern is: is it faster by doing that or try-catch will slow down the function and the performance just the same?

try/catch is only going to be more efficient in situations where no error is thrown. And, let's be clear, with modern clients, the increase in efficiency is going to be marginal and probably not noticeable in most applications.
When errors are thrown, performance will suffer because an error object is instantiated and configured, a scope is created for that error object to exist within and (of course) the JS runtime has to recover from the error.
In my experience, try/catch is generally used incorrectly in the first place. It should not be a matter of "choice" to use try/catch, it should be a matter or necessity. If there is a chance your code can cause an error and there is a way for you to code it to avoid that error, do that - - no try/catch needed.
Examples:
Errors that can occur because of bad user input should be dealt with
by re-thinking the UI and how the input is processed.
Errors that can occur because of a bad interaction with a remote
source (think AJAX) generally have error and timeout callback
options.
If there is a way for your code to throw an error and it is beyond the control of your code (network outage, server error), try/catch may be necessary. I say may because many APIs these days have error callback functions to handle these kinds of things.
In short, you should never just choose try/catch. try/catch is a language feature to be used when no other solution is available.

Related

volatile variable error in Chrome's JS engine?

According to my understanding, in JS there are not race conditions for synchronous code. That is, during the execution of a function variables should only be accessed by 1 executing thread.
However, I have run across this:
In this image you can observe how the predicate of the if statement in line 186 evaluates to true. The code inside the if statement contains only a return statement. Hence, there is no way the thread could have escaped the if statement.
Some context into what sort of functions are calling into this:
This is a service worker MV3 extension.
A number of function stacks are awaiting for the closePromise. Once the close promise resolves, my premise is that the first "thread" to call __innitialize will pass the if statements into the executing thread. When the next "thread" calls __initialize, then the first one would have changed the state to INITIALIZING, thus he would enter the first if statement, and await for the initPromise.
I may not provide anymore than this snippet due to company policy.
(V8 developer here.)
I agree that concurrent modification can't happen in JavaScript. The other obvious explanation (that the JS engine incorrectly checked the condition) would be a severe (and pretty obvious!) bug.
But without further information or a repro, it's hard to say anything for sure. For instance, if this is an embedder-provided object and .__state is an intercepted property, then anything could happen, and it's entirely outside of V8's control. You also mention "sleeping" in the comment: sleeping (and awaiting) are interruptions of synchronous control flow, so if you have such things in your code, that could also explain why things appear to "magically" change after such a point.

Why would an exception cause resource leaks in Node.js?

If you look at the beginning of the Node.js documentation for domains it states:
By the very nature of how throw works in JavaScript, there is almost never any way to safely "pick up where you left off", without leaking references, or creating some other sort of undefined brittle state.
Again in the code example it gives in that first section it says:
Though we've prevented abrupt process restarting, we are leaking resources like crazy
I would like to understand why this is the case? What resources are leaking? They recommend that you only use domains to catch errors and safely shutdown a process. Is this a problem with all exceptions, not just when working with domains? Is it a bad practice to throw and catch exceptions in Javascript? I know it's a common pattern in Python.
EDIT
I can understand why there could be resource leaks in a non garbage collected language if you throw an exception because then any code you might run to clean up objects wouldn't run if an exception is thrown.
The only reason I can imagine with Javascript is if throwing an exception stores references to variables in the scope where the exception was thrown (and maybe things in the call stack), thus keeping references around, and then the exception object is kept around and never gets cleaned up. Unless the leaking resources referred to are resources internal to the engine.
UPDATE
I've Written a blog explaining the answer to this a bit better now. Check it out
Unexpected exceptions are the ones you need to worry about. If you don't know enough about the state of the app to add handling for a particular exception and manage any necessary state cleanup, then by definition, the state of your app is undefined, and unknowable, and it's quite possible that there are things hanging around that shouldn't be. It's not just memory leaks you have to worry about. Unknown application state can cause unpredictable and unwanted application behavior (like delivering output that's just wrong -- a partially rendered template, or an incomplete calculation result, or worse, a condition where every subsequent output is wrong). That's why it's important to exit the process when an unhandled exception occurs. It gives your app the chance to repair itself.
Exceptions happen, and that's fine. Embrace it. Shut down the process and use something like Forever to detect it and set things back on track. Clusters and domains are great, too. The text you were reading is not a caution against throwing exceptions, or continuing the process when you've handled an exception that you were expecting -- it's a caution against keeping the process running when unexpected exceptions occur.
I think when they said "we are leaking resources", they really meant "we might be leaking resources". If http.createServer handles exceptions appropriately, threads and sockets shouldn't be leaked. However, they certainly could be if it doesn't handle things properly. In the general case, you never really know if something handles errors properly all the time.
I think they are wrong / very misleading when they said "By the .. nature of how throw works in JavaScript, there is almost never any way to safely ..." . There should not be anything about how throw works in Javascript (vs other languages) that makes it unsafe. There is also nothing about how throw/catch works in general that makes it unsafe - unless of course you use them wrong.
What they should have said is that exceptional cases (regardless of whether or not exceptions are used) need to be handled appropriately. There are a few different categories to recognize:
A. State
Exceptions that occur while external state (database writing, file output, etc) is in a transient state
Exceptions that occur while shared memory is in a transient state
Exceptions where only local variables might be in a transient state
B. Reversibility
Reversible / revertible state (eg database rollbacks)
Irreversible state (Lost data, unknown how to reverse, or prohibitive to reverse)
C. Data criticality
Data can be scrapped
Data must be used (even if corrupted)
Regardless of the type of state you're messing with, if you can reverse it, you should do that and you're set. The problem is irreversible state. If you can destroy the corrupted data (or quarantine it for separate inspection), that is the best move for irreversible state. This is done automatically for local variables when an exception is thrown, which is why exceptions excel at handling errors in purely functional code (ie functions with no possible side-effects). Likewise, any shared state or external state should be deleted if that's acceptable. In the case of shared state, either throw exceptions until that shared state becomes local state and is cleaned up by unrolling of the stack (either statically or via the GC), or restart the program (I've read people suggesting the use of something like nodejitsu forever). For external state, this is likely more complicated.
The last case is when the data is critical. Well, then you're gonna have to live with the bugs you've created. Everyone has to deal with bugs, but its the worst when your bugs involve corrupted data. This will usually require manual intervention (reconstructing the lost/damaged data, selectively pruning, etc) - exception handling won't get you the whole way in the last case.
I wrote a similar answer related to how to handle mid-operation failure in various cases in the context of multiple updates to some data storage: https://stackoverflow.com/a/28355495/122422
Taking the sample from the node.js documentation:
var d = require('domain').create();
d.on('error', function(er) {
// The error won't crash the process, but what it does is worse!
// Though we've prevented abrupt process restarting, we are leaking
// resources like crazy if this ever happens.
// This is no better than process.on('uncaughtException')!
console.log('error, but oh well', er.message);
});
d.run(function() {
require('http').createServer(function(req, res) {
handleRequest(req, res);
}).listen(PORT);
});
In this case you are leaking connections when an exception occurs in handleRequest before you close the socket.
"Leaked" in the sense that you finished processing the request without cleaning up afterwards. Eventually the connection will time out and close the socket, but if your server is under high load it may run out of sockets before that happens.
Depending on what you do in handleRequest you may also be leaking file handles, database connections, event listeners, etc.
Ideally you should handle your exceptions so you can clean up after them.

What's the advantage of returning exceptions over using try catch blocks in async callback chain?

After looking at Twisted's Deferred class and HeavyLifters Deferred Library I noticed that errbacks are fired if the previous resultant value was an instance of the Failure class. This got me thinking: is there any particular reason for returning a special object to denote an error instead of just throwing an error.
From what I deduced I feel it's better to throw errors because:
Any value can be thrown.
If the value thrown is not caught, it propagates up the call stack.
There's no need for a special Failure or Error class.
It makes the callbacks look more like synchronous code.
The exception may be handled at any level of the call stack.
Some of the disadvantages I noticed were:
Trying blocks of code and catching error may cause a performance hit to the code.
If an exception is not caught then it stops the execution of the rest of the callback chain.
Asynchronous programming is essential the polar opposite of using try catch blocks.
I'm trying to weigh the odds and figure out which method of reporting errors is more suitable in this scenario.
The Failure class in Twisted has a number of handy methods that make it useful, independent of the features in Deferred for running error handling callbacks. Browse the API documentation and you'll find useful methods, for example for formatting tracebacks and checking exception types. Failure is also a handy place to put some really gross hacks for getting nice integration with generators for twisted.internet.defer.inlineCallbacks and for special support code for Cython which generates subtly different exceptions.
Failure is also a good place to keep the traceback state together with the exception. Python exceptions normally don't carry stack information, so if you only have an exception, you can't find out where it was raised. That can be a major drawback any time you want to handle an exception outside of the except block that caught it.
Finally, being able to return a Failure enables this simple, commonly useful pattern:
def handleOneErrorCase(reason):
if not thisCaseApplies(reason):
return reason
handleThisCase(reason)
someDeferred.addErrback(handleOneErrorCase)
This frequently shows up in Deferred-using code. It's convenient, happens to be a bit more performant on CPython, and also has the advantage that the original stack information in reason is preserved (if the exception were re-raised by the error handler, the stack at that point would replace the original stack, obscuring the original cause of the exception).
Errors are usually returned with callback in an async environment as errors cannot be caught outside the async function. For example in javascript if you try:
try {
setTimeout(function() { throw new Error(); }, 0);
} catch (e) {
console.log('Caught it.');
}
Then the exception will go uncaught. This has to do with the fact that async functions are reregistered and then later called by the event loop in a different stack and as such the exception won't bubble up the original stack.

JS library best practice: Return undefined or throw error on bad function input?

When coding a library in JavaScript, what is the most standard (friendliest?) way to handle invalid input to a function? My gut tells me that returning undefined is perfectly fine, but is it actually more helpful to throw an error instead? Or does it really not matter?
I could also see returning false, null or even -1, but I don't think those would be as widely expected.
(If this question is too subjective, I'm happy to make it cw.)
I think undefined is fine but keep in mind that:
JavaScript does not have a void type, so every function must return a
value. The default value is undefined, except for constructors, where
the default return value is this.
So you don't need to explicitly returns undefined. It will be by default.
see http://javascript.crockford.com/survey.html
Advantages of exceptions:
If an error is a rare occurrence (not expected in normal operation), then it may be easier and faster for the calling code to catch exceptions in one higher-level place rather than test return values after every API call.
Disadvantages of exceptions:
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.
If the calling code is going to check errors on every API call they make (and not catch exceptions at a higher level), exceptions are more of a pain to write around every single API call than just testing a return value.
maybe obvious
If you extending an environment - continue their practice as a minimum
Quick answer.
If this is javascript in the browser undefined is OK, if it is javascript in the server throw an error.
Improved
Let the library user select the behavior as an option, either library global, or on an object by object basis.

How to ensure a WebSocket message is JSON string, preventing JSON.parse error?

I've looked around for a suitable method to catch or prevent invalid JSON.parse calls, specifically in the case of WebSocket messages that don't involve type/catch block due to its performance hit.
I've almost fully moved my RESTful API to pure WebSocket API using JSON for communications. The only problem is, I can't figure out how to prevent JSON.parse from halting the app when a malformed message string is put through my onmessage function. All messages sent from the server are theoretically proper JSON that's been stringified, so the question also is, is this an edge case to worry about? Since the function thats used to send data from the serverside JSON stringifies before sending.
I'm using React and Redux with redux-thunk to open a WebSocket and add event listeners, so on a message the function below is being run.
function onMessage(msg) {
const data = JSON.parse(msg.data);
return {
type: data.type,
data: data.data
}
}
But this, of course, breaks if msg is not a valid JSON string then halting execution of the app.
So, without a try/catch block, is the only option to (somehow) ensure valid JSON is being sent? Or is this an edge case I shouldn't be worried about.
EDIT
This may not be such a big issue for client side since all messages are coming from a centralized point (the server), though on the other hand, quite a big issue for the server, seeing it's possible it to receive messages that have not been sent from the application.
Is try/catch really the devil it's made out to be? Since the only thing I can think of is to create a regex check, which in itself would end up becoming quite complicated.
don't involve type/catch block due to its performance hit.
Forget the myths. You want to catch an exception, like the one from JSON.parse, you use a try/catch block. It's that simple and not a significant performance hit. Of course you could also write your own logic to validate JSON strings (not with regex!), but that's gonna be a complete parser which just doesn't use exceptions to signal malformed input - and much slower than the native function.
Is this an edge case to worry about?
On the client, hardly. You're controlling the server and making sure to send only valid JSON strings. If you don't, I'd worry much more about the server than about a few clients crashing. The users will most likely reload the page and continue.
Though on the other hand, quite a big issue for the server, seeing it's possible it to receive messages that have not been sent from the application.
Yes. On the server you absolutely need to worry about malformed input. If sending invalid JSON makes your server crash, that's really bad.

Categories