I get the error in the title from this code:
try {
let n = undefined;
let nx = n?.x;
} catch (err) {
missingFeatures.push("Syntax n?.x not recognized");
}
As you can see the code is designed with the hope to catch support for this syntax.
But it does not work. Is there any way to catch this syntax error?
A bit interesting is that this happens in the new chromium based Edge on Android 10.
You can construct a new Function instead, and see if the construction of the function throws. There's no need to define the other variables first, since all you care about is whether the syntax is proper, and syntax checking doesn't care whether the variables are defined, since the function never gets run:
try {
const fn = new Function('n?.x');
} catch (err) {
missingFeatures.push("Syntax n?.x not recognized");
}
That said, testing for whether a particular syntax is supported is pretty odd. Unless you're writing something dev-oriented for the user (like a live JavaScript editor), it would almost always make more sense to simply transpile your code down to ES5 or ES6 for production and serve that to everyone.
Related
As we all know, we can easy to see the line of an output statement in the browser, just like follow picture
enter image description here
but in the nodejs env, how do I know what line is 'output statement' in.
I have this need because I want to know better during development where the information is coming from when the program fails. Of course, I could have each output statement carry a unique character, like console.log('1', '...'), console.log('2', '...') but that feels silly and unhackable to me.
I'll show you a simple piece of code as an illustration
try {
throw new Error('something error')
} catch (error) {
console.log(error.stack)
}
Run the above code I can see the output:
Error: something error
at file:///c:/Users/Linhieng/Desktop/tmp/a.js:2:9
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:61:12)
the above output tell us what line is the error in, but I want to know the line of console.log.
You can monkeypatch console.log with code that parses the stack string, since this is Node.js and the format only varies across releases (unlike on browsers, where it can vary by browser as well):
const realLog = console.log;
console.log = (...msgs) => {
try {
throw new Error("something error");
} catch (error) {
const lines = error.stack.split(/(?:\r\n|\r|\n)+/);
msgs.push(`[${lines[2].trim()}]`);
}
realLog(...msgs);
};
Then for instance, this:
function example() {
console.log("Hi there");
}
example();
shows
Hi there [at example (file:///____/temp.js:13:13)]
At present, the "parsing" is really easy — just split on newlines and take the third element of the array. But you might want to extract more information, or the format could change in future versions to require more complicated "parsing."
I thing woth simple logging the only solution here is a manually passing the according line number. Something like that:
console.log(error, LINE_NUMBER);
Another possible solution probably could be when you use some kind of a external configurable NodeJS debugger software. There probably will be provided a functionality related you your needs.
I am using try catch inside try block to print relative message or get to know in which method error happened.
code snippet
for (const searchUrl of savedSearchUrls) {
console.log("here");
// function will get all the links of profiles in saved search url
try {
const links = await scrapeFromurl(browser, searchUrl);
try {
saveToDatabase(links);
} catch (e) {
handleError(e, "eror while saving to database");
}
} catch (err) {
handleError(err, "error in scrapeFromurl()");
}
}
I have searched on google but couldn't find related topic.
what are the other ways to accomplish similar things?
what are the best practice to handle this type of situation.
I would suggest using only one try catch block and specific error instances for each method, then in catch block you can simply check which method throws an error by using instanceof operator
class ScrapeError extends Error {
message = "error in scrapeFromurl()"
}
class DBError extends Error {
message = "eror while saving to database"
}
async function scrapeFromurl() {
throw new ScrapeError();
}
async function saveToDatabase(links) {
throw new DBError();
}
async function main() {
try {
const links = await scrapeFromurl();
await saveToDatabase(links);
} catch (e) {
if (e instanceof ScrapeError) {
console.log('scrape', e);
}
if (e instanceof DBError) {
console.log('dberror', e);
}
}
}
main();
By default a single try-catch block is enough without needs for nesting other try-catches into it. However, there may be some legitimate exceptions from these rules.
Exception 1: Different handlers for the same exception
Let's consider the following example
try {
myroutine(); // may throw three types of exceptions
} catch (e) {
if (e instanceof TypeError) {
// statements to handle TypeError exceptions
} else if (e instanceof RangeError) {
// statements to handle RangeError exceptions
} else if (e instanceof EvalError) {
// statements to handle EvalError exceptions
} else {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
}
It is perfectly possible that inside your try there is a section where a given error type, like a RangeError needs a different way of handling than the main catch. In this case it might make sense to have another try-catch inside your try, albeit, in this case, for better readability it would make sense to consider the inner try as a method and call that, so you would not physically nest the try-catch blocks, but separate the concerns of the try-catches into separate methods.
Exception 2: Handling a certain type of error only at a section of a try-block
It is quite possible that you want your try-catch to throw the error further in the majority of your try block, but, in a specific section you want it to handle it. Again, in this case it would make sense to separate the inner try into its own method.
Conclusion
Having nested try-catches are nonintuitive for a reader, therefore it makes sense to separate the inner try into its own method whenever you encounter the need to nest tries. Yet, as the examples above show, there are legitimate needs to drift away from the outer handling of an error for some sections. However, by default it is a good idea to consider such sections as separate concerns worthy of separating from the method. Of course, sometimes you might want to keep nested try-catches without separating their concerns, but more often than not it is worth to apply the separations. So, a rule of thumb that you may want to consider is to refactor nested try-catches either into separate methods or a single try-catch, unless there is a very good reason not to do so.
In asyncronous scripts you can use domains for error handling. And trycatch in trycatch can be treated like domain in domain, which is pointless.
Moreover, programmers always tend to prevent the code from growing horizontally like this
{
...
{
...
{
... (and so on)
{
}
}
}
}
So it is a really bad idea. I can keep on telling drawbacks of this approach, but not going to. Just use one trycatch with switchcase inside to handle all errors
I'm trying to get the error code when I catch an error, but it's always undefined.
How do I get the error code?
Here are two examples:
try {
const f = 4;
f = 9;
} catch (err) {
console.log(err.code);
console.log(err.message);
}
try {
d = 12;
} catch (err) {
console.log(err.code);
console.log(err.message);
}
Console:
undefined
Assignment to constant variable.
undefined
d is not defined
I work on Node.js v14.17.1.
As the others commented try console.log(err) to see what the object looks like before trying to select properties from it.
I misunderstood the question with my original answer. To my understanding there is no .code property on the error object returned within a try catch block. Check out this documentation https://javascript.info/try-catch#error-object and try error.name.
A standard Javascript/Ecmascript error has no code property. See the Error docs for details.
The link you provide, from Node's Errors documentation pertains only to custom errors thrown by Node.js — Javascript errors thrown by, say, V8 will adhere to Javascript standard referenced in the 1st link above.
In this function that handles a REST API call, any of the called functions to handle parts of the request might throw an error to signal that an error code should be sent as response. However, the function itself might also discover an error, at which point it should jump into the exception handling block.
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
throw new ForbiddenException("You're not allowed to do that.");
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
Webstorm will underline the throw with the following message: 'throw' of exception caught locally. This inspection reports any instances of JavaScript throw statements whose exceptions are always caught by containing try statements. Using throw statements as a "goto" to change the local flow of control is likely to be confusing.
However, I'm not sure how to refactor the code to improve the situation.
I could copypaste the code from the catch block into the if check, but I believe this would make my code less readable and harder to maintain.
I could write a new function that does the isAllowed check and throws an exception if it doesn't succeed, but that seems to be sidestepping the issue, rather than fixing a design problem that Webstorm is supposedly reporting.
Are we using exceptions in a bad way, and that's why we're encountering this problem, or is the Webstorm error simply misguiding and should be disabled?
Contrary to James Thorpe's opinion, I slightly prefer the pattern of throwing. I don't see any compelling reason to treat local errors in the try block any differently from errors that bubble up from deeper in the call stack... just throw them. In my opinion, this is a better application of consistency.
Because this pattern is more consistent, it naturally lends itself better to refactoring when you want to extract logic in the try block to another function that is perhaps in another module/file.
// main.js
try {
if (!data) throw Error('missing data')
} catch (error) {
handleError(error)
}
// Refactor...
// validate.js
function checkData(data) {
if (!data) throw Error('missing data')
}
// main.js
try {
checkData(data)
} catch (error) {
handleError(error)
}
If instead of throwing in the try block you handle the error, then the logic has to change if you refactor it outside of the try block.
In addition, handling the error has the drawback of making you remember to return early so that the try block doesn't continue to execute logic after the error is encountered. This can be quite easy to forget.
try {
if (!data) {
handleError(error)
return // if you forget this, you might execute code you didn't mean to. this isn't a problem with throw.
}
// more logic down here
} catch (error) {
handleError(error)
}
If you're concerned about which method is more performant, you shouldn't be. Handling the error is technically more performant, but the difference between the two is absolutely trivial.
Consider the possibility that WebStorm is a bit too opinionated here. ESLint doesn't even have a rule for this. Either pattern is completely valid.
You're checking for something and throwing an exception if isAllowed fails, but you know what to do in that situation - call sendErrorCode. You should throw exceptions to external callers if you don't know how to handle the situation - ie in exceptional circumstances.
In this case you already have a defined process of what to do if this happens - just use it directly without the indirect throw/catch:
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
sendErrorCode("You're not allowed to do that.");
return;
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
I could copypaste the code from the catch block into the ifcheck, but I believe this would make my code less readable and harder to maintain.
On the contrary, as above, I would expect this to be the way to handle this situation.
Since this is not a blocking error, but only an IDE recommendation, then the question should be viewed from two sides.
The first side is performance. If this is a bottleneck and it is potentially possible to use it with compilation or when transferring to new (not yet released) versions of nodejs, the presence of repetitions is not always a bad solution. It seems that the IDE hints precisely in this case and that such a design can lead to poor optimization in some cases.
The second side is the code design. If it will make the code more readable and simplify the work for other developers - keep it. From this point of view, solutions have already been proposed above.
Return a promise reject instead of throwing error in the try block
try {
const isAllowed = await checkIfIsAllowed(request);
if (!isAllowed) {
return Promise.reject(Error("You're not allowed to do that."));
}
const result = await doSomething(request);
sendResult(result);
} catch (error) {
throw error;
}
There are good answers to the question "Why not use exceptions as normal flow control?" here.
The reason not to throw an exception that you will catch locally is that you locally know how to handle that situation, so it is, by definition, not exceptional.
#James Thorpe's answer looks good to me, but #matchish feels it violates DRY. I say that in general, it does not. DRY, which stands for Don't Repeat Yourself, is defined by the people who coined the phrase as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system". As applied to writing software code, it is about not repeating complex code.
Practically any code that is said to violate DRY is said to be "fixed" by extracting the repeated code into a function and then calling that function from the places it was previously repeated. Having multiple parts of your code call sendErrorCode is the solution to fixing a DRY problem. All of the knowledge of what to do with the error is in one definitive place, namely the sendErrorCode function.
I would modify #James Thorpe's answer slightly, but it is more of a quibble than a real criticism, which is that sendErrorCode should be receiving exception objects or strings but not both:
static async handleRequest(req) {
try {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
sendErrorCode(new ForbiddenException("You're not allowed to do that."));
return;
}
let result = await doSomething(req); // can also raise exceptions
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
The larger question is what is the likelihood of the error and is it appropriate to treat !isAllowed as an exception. Exceptions are meant to handle unusual or unpredictable situations. I would expect !isAllowed to be a normal occurrence that should be handled with logic specific to that situation, unlike, say, a sudden inability to query the database that has the answer to the isAllowed question.
#matchish's proposed solution changes the contract of doSomethingOnAllowedRequest from something that will never throw an exception to something that will routinely throw an exception, placing the burden of exception handling on all of its callers. This is likely to cause a violation of DRY by causing multiple callers to have repetitions of the same error handling code, so in the abstract I do not like it. In practice, it would depend on the overall situation, such as how many callers are there and do they, in fact, share the same response to errors.
Answer of James Thorpe has one disadvantage on my opinion. It's not DRY, in both cases when you call sendError you handle Exceptions. Let's imagine we have many lines of code with logic like this where Exception can be thrown. I think it can be better.
This is my solution
async function doSomethingOnAllowedRequest(req) {
let isAllowed = await checkIfIsAllowed(req);
if (!isAllowed) {
throw new ForbiddenException("You're not allowed to do that.");
}
doSomething(req);
}
static async handleRequest(req) {
try {
let result = await doSomethingOnAllowedRequest(req);
sendResult(result);
} catch(err) {
sendErrorCode(err);
}
}
This could give you some tips, maybe that can be the cause(not sure if relevant).
Catch statement does not catch thrown error
"
The reason why your try catch block is failing is because an ajax request is asynchronous. The try catch block will execute before the Ajax call and send the request itself, but the error is thrown when the result is returned, AT A LATER POINT IN TIME.
When the try catch block is executed, there is no error. When the error is thrown, there is no try catch. If you need try catch for ajax requests, always put ajax try catch blocks inside the success callback, NEVER outside of it."
Recently I had a discussion with my coworker, about using try and catch to notify errors or avoid them.
This is my coworker's approach:
import Config from 'config';
export const getUserFromLocalStorage = () => {
const key = Object.keys(localStorage).find(value => value === `${Config.applicationId}/currentUser`);
try {
return key ? JSON.parse(localStorage[key]) : {};
} catch (e) {
return {};
}
};
Wich means, he doesn't care about the given error and he is just carrying of returning an object in order to continue the process
and mine is:
import Config from 'config';
export const getUserFromLocalStorage = () => {
const key = Object.keys(localStorage).find(value => value === `${Config.applicationId}/currentUser`);
try {
return key ? JSON.parse(localStorage[key]) : {};
} catch (e) {
console.log('the given error', e); // Just simple notifier for this example
}
};
but my approach, still has a problem which is that it will return undefined (which can crash internaly my app), that can easily fix it using finally and returning a default value but it doesn't sound a good practice to me.
THE QUESTION
So what will the balance using try catch and finally if needed, to make my application stable.
Is there something wrong with our approach?
In particular, we can't trust the data that is comming from the localStorage, so what will be the best approach for this implementation?
Since finally is executed in either case, whether something was thrown or not, it is not the place to return a default value. It is also questionable whether you need to log the error in great detail or not. It all depends on whether something is an expected error or a truly exceptional circumstance and who can do something about it.
Is it rather likely or possible that the value stored is invalid JSON? And you have a "backup plan" for what to do in that case? And there's nothing the user and/or developer can do about it? Then don't bother anyone with it. Maybe you want to console.log a message that might aid in debugging, but other than that just carry on with the program flow. There's most certainly no need to bug the user with an alert if a) the user didn't initiate the action and b) there's nothing for them to do about it either.
Considerations to take:
Whether to catch an error in the first place:
is it an expected error which may naturally occur during the program flow?
is it an error you can do something about?
do you have any plan what to do if you caught the error?
Whether to log an error:
does this log do anyone any good?
will anybody ever see that log entry?
does it give anyone any useful information that can lead to fixing the issue?
Whether to bug the user about something:
did the user initiate the action?
does the user expect some form of response, positive or negative?
can the user do anything to fix the problem?
Whether to return an empty object or nothing/null/undefined depends on what the function's responsibility is. Is the function defined to always return an object? Then it should return {} from catch. Or is "nothing" a valid response when the expected object doesn't exist? Then perhaps return false.
Overall, your coworker's approach seem very reasonable to me.
In this specific case, where you are working with localStorage (which almost always inevitably means working with JSON.parse()), it's always best practice to wrap your processing in try-catch. This is because both localStorage and JSON.parse have exceptions as a normal part of their error handling and it is usually possible to fallback to a default or initial value gracefully.
A pattern I use is something like as follows:
const DEFAULT_VALUE = {};
try {
const result = JSON.parse(result);
return result || DEFAULT_VALUE;
} catch (e) {
console.warn('Error parsing result', e);
}
return DEFAULT_VALUE;
This way, you have consistent error handling and default value fallback.
In general, you shouldn't need use try-catch unless you can and will safely handle the error and generate a useful fallback. Most try-catch blocks tend to sit at the bottom of a call-stack for this reason, so that they catch unplanned errors, handle them gracefully for the user, but log them noisily with a call-stack to the console for the developer to investigate/handle correctly/workaround.
I think the most important thing is that user satisfaction. At the end of the day, the program is used by the normal user. The user needs to continue his work using the program without any interruptions.
So i think that the best practices is to use try to run code and catch if there any errors and notify developer and/or user that there is an exception, and use finally to overcome the exception by returning a valid object.
In this way user is also able to continue the work and the developer also can check the error in log file for future debugging.
This is my personal idea.