in

The Ultimate Guide to JavaScript Error Handling — SitePoint

1674711853javascript error handling

[ad_1]

This tutorial takes a deep dive into error handling in JavaScript, allowing you to throw, detect, and handle your own errors.

content:

  1. Displaying an error message is a last resort
  2. How JavaScript handles errors
  3. catching exceptions
  4. Standard JavaScript error types
  5. AggregateError
  6. throw your own exception
  7. async function error
  8. Promise-based errors
  9. exceptional exception handling

Expert developers expect the unexpected. If something goes wrong, it goes wrong – Usually the moment the first user accesses a new web system.

You can avoid web application errors such as:

  • A good editor or linter can catch syntax errors.
  • Proper validation can catch user input errors.
  • A robust testing process can find logic errors.

Still the error remains. Your browser may fail or not support the API you’re using. The server may fail or take too long to respond. Network connections may fail or become unreliable. The problem may be temporary, but I can’t code a way around such problems. However, you can anticipate problems and take corrective action to make your application more resilient.

Displaying an error message is a last resort

Ideally, the error message should not be displayed to the user.

Minor issues such as failure to load decoration images can be ignored. Storing data locally and uploading it later can help with more serious issues such as Ajax data save failures. Errors are needed only when the user is at risk of losing data — Assuming they can do something about it.

Therefore, you should catch any errors that occur and determine the best course of action. Raising and catching errors in your JavaScript application can be daunting at first, but it may be easier than you think.

How JavaScript handles errors

When a JavaScript statement results in an error, throw an exception. JavaScript is Error An object describing the error. You can see this in action in this CodePen demo.When set decimal place A negative number will display an error message at the bottom of the console. (Note that this tutorial does not embed CodePens. This is because I need to be able to see the console output to make sense of it.)

Results are not updated. RangeError console message. The following function throws an error if: dp is negative:


function divide(v1, v2, dp) {

  return (v1 / v2).toFixed(dp);

}

After throwing an error, the JavaScript interpreter checks the exception handling code.nothing exists in divide() Since it’s a function, it checks the calling function.


function showResult() {

  result.value = divide(
    parseFloat(num1.value),
    parseFloat(num2.value),
    parseFloat(dp.value)
  );

}

The interpreter repeats the process for every function on the call stack until one of the following occurs:

  • find the exception handler
  • It reaches the top level of the code (the program exits and an error is printed to the console, as shown in the CodePen example above).

catching exceptions

the exception handler divide() A function with a try…catch block:


function divide(v1, v2, dp) {
  try {
    return (v1 / v2).toFixed(dp);
  }
  catch(e) {
    console.log(`
      error name   : ${ e.name }
      error message: ${ e.message }
    `);
    return 'ERROR';
  }
}

This will try {} Blocks, but when an exception occurs, catch {} The block executes and receives the thrown error object.Try to set as before decimal place Make it a negative number for this CodePen demo.

of result now show error. The console shows the error name and message, which is console.log Do not terminate the program.

Note: For this demonstration try...catch Blocks are overkill for basic functionality like divide(). Easier to check dp Greater than or equal to zero, as shown below.

You can define options finally {} Block if code should be executed in any of the following cases try Also catch Code is executed:

function divide(v1, v2, dp) {
  try {
    return (v1 / v2).toFixed(dp);
  }
  catch(e) {
    return 'ERROR';
  }
  finally {
    console.log('done');
  }
}

console output "done", whether the computation succeeds or an error occurs.Ah finally Blocks typically perform actions that would otherwise need to be repeated on both try and the catch Blocking — such as canceling an API call or closing a database connection.

Ah try Block must have one of catch block, finally block, or both. be careful. finally in the block return statement, whose value becomes the return value of the entire function.other return statement of try Also catch Blocks are ignored.

nested exception handler

What happens when you add an exception handler to the caller showResult() function?


function showResult() {

  try {
    result.value = divide(
      parseFloat(num1.value),
      parseFloat(num2.value),
      parseFloat(dp.value)
    );
  }
  catch(e) {
    result.value = 'FAIL!';
  }

}

The answer is… none! this catch Blocks are never reached. catch block of divide() The function handles errors.

However, programmatically new Error object divide() optionally return the original error to cause Properties of the second argument:

function divide(v1, v2, dp) {
  try {
    return (v1 / v2).toFixed(dp);
  }
  catch(e) {
    throw new Error('ERROR', { cause: e });
  }
}

This will catch Calling function block:


function showResult() {

  try {
    
  }
  catch(e) {
    console.log( e.message ); 
    console.log( e.cause.name ); 
    result.value = 'FAIL!';
  }

}

Standard JavaScript error types

When an exception occurs, JavaScript creates and throws an object describing the error using one of the following types:

syntax error

Errors thrown by syntactically invalid code, such as missing parentheses:

if condition) { 
  console.log('condition is true');
}

Note: Languages ​​such as C++ and Java report syntax errors during compilation. JavaScript is an interpreted language, so syntax errors are not identified until the code is executed. A good code editor or linter can catch syntax errors before the code is even run.

reference error

Error thrown when accessing a non-existent variable:

function inc() {
  value++; 
}

Again, good code editors and linters can spot these issues.

TypeError

Error thrown when a value is not of the expected type, such as calling a non-existent object method:

const obj = {};
obj.missingMethod(); 

range error

The error thrown when the value is not within the set or range of allowed values. The toFixed() method used above produces this error because it normally expects a value between 0 and 100.

const n = 123.456;
console.log( n.toFixed(-1) ); 

URI error

Errors thrown by URI handling functions such as encodeURI() and decodeURI() when encountering a malformed URI:

const u = decodeURIComponent('%'); 

EvalError

Error thrown when passing a string containing invalid JavaScript code to the eval() function:

eval('console.logg x;'); 

Note: don’t use eval()! Executing arbitrary code contained in strings that may have been constructed from user input is extremely dangerous!

AggregateError

The error thrown when multiple errors are wrapped into a single error. This typically happens when calling operations such as Promise.all() that return results from an arbitrary number of promises.

internal error

Non-standard (Firefox only) error thrown when an error occurs inside the JavaScript engine. This is usually the result of something taking up too much memory, such as a large array or “too much recursion”.

error

Finally, there are generics Error Objects are most often used when implementing your own exceptions. This is explained next.

throw your own exception

we can throw Own exception in case of error — or must occur. for example:

  • No valid parameters passed to function
  • Ajax request does not return expected data
  • DOM update fails because node does not exist

of throw The statement actually accepts any value or object. for example:

throw 'A simple error string';
throw 42;
throw true;
throw { message: 'An error', name: 'MyError' };

An exception is thrown to every function on the call stack until it is intercepted by an exception (catch) handler.However, more practically, you’ll want to create and throw Error It behaves like the standard error thrown by JavaScript.

You can create generics Error Create an object by passing an optional message to the constructor.

throw new Error('An error has occurred');

You can also use Error like a function without newreturns . Error Same object as above:

throw Error('An error has occurred');

Optionally, you can pass the file name and line number as second and third parameters.

throw new Error('An error has occurred', 'script.js', 99);

This is rarely needed. Error object. (It’s also difficult to maintain them as the files change!)

You can define generics Error Object, but should use standard error types if possible. for example:

throw new RangeError('Decimal places must be 0 or greater');

all Error The object has the following properties, catch block:

  • .name: the name of the error type — etc. Error Also RangeError
  • .message: Error message

The following non-standard properties are also supported by Firefox:

  • .fileName: the file where the error occurred
  • .lineNumber: line number where the error occurred
  • .columnNumber: column number of the line where the error occurred
  • .stack: a stack trace listing the function calls made before the error occurred

we can change divide() a function that throws RangeError If decimal places are not numeric, less than 0, or greater than 8:


function divide(v1, v2, dp) {

  if (isNaN(dp) || dp < 0 || dp > 8) {
    throw new RangeError('Decimal places must be between 0 and 8');
  }

  return (v1 / v2).toFixed(dp);
}

Similarly, Error Also TypeError when dividend value is not a number to prevent NaN result:

  if (isNaN(v1)) {
    throw new TypeError('Dividend must be a number');
  }

It is also possible to correspond divisor is non-numeric or zero. JavaScript returns Infinity when dividing by zero, which can confuse users.Rather than raise generics Errorcan create custom DivByZeroError Error type:


class DivByZeroError extends Error {
  constructor(message) {
    super(message);
    this.name = 'DivByZeroError';
  }
}

Then toss it the same way.

if (isNaN(v2) || !v2) {
  throw new DivByZeroError('Divisor must be a non-zero number');
}

Add now try...catch block the call showResult() function.receive as much Error Type and react accordingly — in this case, display an error message:


function showResult() {

  try {
    result.value = divide(
      parseFloat(num1.value),
      parseFloat(num2.value),
      parseFloat(dp.value)
    );
    errmsg.textContent = '';
  }
  catch (e) {
    result.value = 'ERROR';
    errmsg.textContent = e.message;
    console.log( e.name );
  }

}

Try entering invalid non-numeric, zero, and negative values ​​in this CodePen demo.

final version of divide() The function checks all input values ​​and Error If necessary:


function divide(v1, v2, dp) {

  if (isNaN(v1)) {
    throw new TypeError('Dividend must be a number');
  }

  if (isNaN(v2) || !v2) {
    throw new DivByZeroError('Divisor must be a non-zero number');
  }

  if (isNaN(dp) || dp < 0 || dp > 8) {
    throw new RangeError('Decimal places must be between 0 and 8');
  }

  return (v1 / v2).toFixed(dp);
}

no longer need to be placed. try...catch block around the final return, because it should not generate an error. If an error occurs, JavaScript generates its own error and catch block in showResult().

async function error

You cannot catch exceptions thrown by callback-based asynchronous functions. try...catch The block completes execution. This code looks correct, but catch The block is never executed and the console shows Uncaught Error Message after 1 second:

function asyncError(delay = 1000) {

  setTimeout(() => {
    throw new Error('I am never caught!');
  }, delay);

}

try {
  asyncError();
}
catch(e) {
  console.error('This will never run');
}

The convention expected by most frameworks and server runtimes such as Node.js is to return the error as the first parameter of the callback function.It doesn’t raise an exception, but you can throw it manually Error If necessary:

function asyncError(delay = 1000, callback) {

  setTimeout(() => {
    callback('This is an error message');
  }, delay);

}

asyncError(1000, e => {

  if (e) {
    throw new Error(`error: ${ e }`);
  }

});

Promise-based errors

Callbacks can get unwieldy, so it’s a good idea to use promises when writing asynchronous code.If an error occurs, the promise’s reject() methods can return new Error Object or other value:

function wait(delay = 1000) {

  return new Promise((resolve, reject) => {

    if (isNaN(delay) || delay < 0) {
      reject( new TypeError('Invalid delay') );
    }
    else {
      setTimeout(() => {
        resolve(`waited ${ delay } ms`);
      }, delay);
    }

  })

}

Note: Functions must be 100% synchronous or 100% asynchronous. For this reason, you should check the following items: delay The value in the returned promise.if we check delay threw value and error Before Returning a promise makes the function synchronous when an error occurs.

The Promise.catch() method is delay Received and returned parameters Error object:


wait('INVALID')
  .then( res => console.log( res ))
  .catch( e => console.error( e.message ) )
  .finally( () => console.log('complete') );

Personally, I find Promise chains a little hard to read.Fortunately, we can use await Call a function that returns a promise. this is, async It’s a function, but you can capture the error using the standard try...catch block.

Below (immediate start) async function is functionally the same as the promise chain above.

(async () => {

  try {
    console.log( await wait('INVALID') );
  }
  catch (e) {
    console.error( e.message );
  }
  finally {
    console.log('complete');
  }

})();

exceptional exception handling

Throw Error Handling objects and exceptions is easy in JavaScript.

try {
  throw new Error('I am an error!');
}
catch (e) {
  console.log(`error ${ e.message }`)
}

Building resilient applications that respond gracefully to errors and make life easier for users is even more difficult. Always expect the unexpected.

Further information:

[ad_2]

Source link

What do you think?

Leave a Reply

GIPHY App Key not set. Please check settings

    ideas ai filters self

    An AI Filter Revealed My Secret Self

    4401bb2a 8c4d 46c3 b7c7 0030224953d2

    The Power of Closures in JavaScript: Understanding and Leveraging Concepts