JavaScript syntax: error handling mechanism

Keywords: Javascript Attribute less REST

1. Error Instance Object

When JavaScript parses or runs, the engine throws an error object whenever an error occurs.JavaScript natively provides the Error constructor, and all errors thrown are examples of this constructor.

var err = new Error('Error');
console.log(err.message); // "Error"

In the code above, we call the Error constructor to generate an instance object, err.The Error constructor accepts a parameter indicating an error prompt, which can be read from the message property of the instance.When an Error instance object is thrown, the entire program interrupts where the error occurs and does not execute further.

The JavaScript language standard only mentions that Error instance objects must have a message attribute that indicates the prompt for an error, not other properties.Most JavaScript engines also provide name and stack properties for Error instances, representing the name of the error and the stack of the error, respectively, but they are nonstandard and not available for every implementation.

  • Message: error message
  • Name: incorrect name (non-standard attribute)
  • Stack: wrong stack (non-standard property)

With the properties name and message, you can get a general idea of what went wrong.

if (error.name) {
  console.log(error.name + ': ' + error.message);
}

The stack property is used to view the stack at which the error occurred.

function throwit() {
  throw new Error('');
}

function catchit() {
  try {
    throwit();
  } catch(e) {
    console.log(e.stack); // print stack trace
  }
}

catchit()
// Error
//    at throwit (~/examples/throwcatch.js:9:11)
//    at catchit (~/examples/throwcatch.js:3:9)
//    at repl:1:5

In the code above, the innermost layer of the error stack is the throwit function, then the catchit function, and finally the environment in which the function runs.

2. Native error type

The Error instance object is the most common type of error on which JavaScript defines six other error objects.That is, there are six derived objects for Error.

2.1 SyntaxError object

The SyntaxError object is a syntax error that occurs when parsing code.

// Variable name error
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token

// Missing parentheses
console.log 'hello');
// Uncaught SyntaxError: Unexpected string

Errors in the above code can be found during the parsing phase, so SyntaxError is thrown.The first error prompt is "token illegal", and the second error prompt is "string does not meet requirements".

2.2 ReferenceError object

The ReferenceError object is an error that occurs when referencing a variable that does not exist.

// Use a variable that does not exist
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined

Another trigger scenario is to assign a value to an unassigned object, such as the result of a function or this assignment.

// The left side of the equal sign is not a variable
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment

// this object cannot be assigned manually
this = 1
// ReferenceError: Invalid left-hand side in assignment

The code above assigns a value to console.log and this, both of which result in a ReferenceError error.

2.3 RangeError object

The RangeError object is an error that occurs when a value exceeds the valid range.There are several main cases, one is that the length of the array is negative, the other is that the method parameter of the Number object is out of range, and the function stack exceeds the maximum value.

// Array length must not be negative
new Array(-1)
// Uncaught RangeError: Invalid array length

2.4 TypeError object

An error occurs when a TypeError object is a variable or an argument is not of the expected type.For example, using the new command on values of the original type, such as strings, Booleans, numbers, and so on, throws this error because the parameters of the new command should be a constructor.

new 123
// Uncaught TypeError: number is not a func

var obj = {};
obj.unknownMethod()
// Uncaught TypeError: obj.unknownMethod is not a function

In the second case of the code above, calling a method where the object does not exist also throws a TypeError error because the value of obj.unknownMethod is undefined, not a function.

2.5 URIError object

The URIError object is an error thrown when the parameters of the URI-related function are incorrect. It mainly involves six functions: encodeURI(), decodeURI(), encodeURIComponent(), decodeURIComponent(), escape(), and unescape().

decodeURI('%2')
// URIError: URI malformed

2.6 EvalError object

When the eval function is not executed correctly, an EvalError is thrown.This error type is no longer used and will be retained only to ensure compatibility with previous code.

2.7 Summary

These six derived errors, along with the original Error object, are constructors.Developers can use them to manually generate instances of error objects.Each of these constructors accepts a parameter representing an error message.

var err1 = new Error('Error!');
var err2 = new RangeError('Error, variable out of range!');
var err3 = new TypeError('Error, invalid variable type!');

err1.message // "Something went wrong!"
err2.message // "Error, variable is out of range!"
err3.message // "Error, invalid variable type!"

3. Customization Errors

In addition to the seven error objects that JavaScript provides natively, you can define your own.

function UserError(message) {
  this.message = message || 'Default information';
  this.name = 'UserError';
}

UserError.prototype = new Error();
UserError.prototype.constructor = UserError;

The code above customizes an error object, UserError, to inherit the Error object.This custom type of error can then be generated.

new UserError('This is a custom error!');

4. throw statement

The throw statement interrupts program execution manually and throws an error.

if (x <= 0) {
  throw new Error('x Must be positive');
}
// Uncaught ReferenceError: x is not defined

In the code above, if the variable x is less than or equal to 0, manually throw an error telling the user that the value of X is incorrect and the whole program will interrupt execution here.You can see that the error throw throws is its parameter, here is an Error instance.

Throw can also throw custom errors.

function UserError(message) {
  this.message = message || 'Default information';
  this.name = 'UserError';
}

throw new UserError('Error!');
// Uncaught UserError {message:'Error!', name:'UserError'}

In the code above, throw throws an instance of UserError.

In fact, throw can throw any type of value.That is, its parameters can be any value.

// Throw a string
throw 'Error!';
// Uncaught Error!

// Throw a value
throw 42;
// Uncaught 42

// Throw a Boolean value
throw true;
// Uncaught true

// Throw an object
throw {
  toString: function () {
    return 'Error!';
  }
};
// Uncaught {toString: ƒ}

For the JavaScript engine, the program aborts when a throw statement is encountered.The engine receives throw throw information, which may be an error instance or another type of value.

5. try...catch structure

Once an error occurs, the program aborts execution.JavaScript provides a try...catch structure that allows you to handle errors and choose whether to execute down or not.

try {
  throw new Error('Error!');
} catch (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: Error!
//   at <anonymous>:3:9
//   ...

In the above code, the try code block throws an error (throw statement is used in the above example), and the JavaScript engine immediately executes the code and goes to the catch code block, or the error is caught by the catch code block.Catch accepts a parameter that represents the value thrown by the try code block.

If you're not sure if some of your code will fail, you can put them in the try...catch block for further error handling.

try {
  f();
} catch(e) {
  // Handling errors
}

In the code above, if function f executes an error, the catch block is executed, and then the error is handled.

After the catch code block captures the error, the program does not interrupt and continues executing as normal.

try {
  throw "Error";
} catch (e) {
  console.log(111);
}
console.log(222);
// 111
// 222

In the above code, the error thrown by the try code block is caught by the catch code block, and the program continues executing down.

You can also throw errors in the catch code block or even use a nested try...catch structure.

var n = 100;

try {
  throw n;
} catch (e) {
  if (e <= 50) {
    // ...
  } else {
    throw e;
  }
}
// Uncaught 100

In the above code, another error is thrown in the catch code.

To catch different types of errors, a judgment statement can be added to the catch code block.

try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}

In the code above, after catch catches an error, it determines the type of error (EvalError or RangeError) and handles it differently.

6. finally block of code

The try...catch structure allows a final block of code to be added at the end, indicating that a statement must be run at the end, regardless of whether an error occurs or not.

function cleansUp() {
  try {
    throw new Error('Something went wrong...');
    console.log('This line will not execute');
  } finally {
    console.log('Complete Cleanup');
  }
}

cleansUp()
// Complete Cleanup
// Uncaught Error: Error...
//    at cleansUp (<anonymous>:3:11)
//    at <anonymous>:10:1

In the above code, because there is no catch statement block, the code will break execution if an error occurs.Before interrupting execution, a final block of code is executed, and then an error message is prompted to the user.

function idle(x) {
  try {
    console.log(x);
    return 'result';
  } finally {
    console.log('FINALLY');
  }
}

idle('hello')
// hello
// FINALLY

In the above code, there are no errors in the try code block and the return statement is included, but the final code block will still execute.Moreover, the return value of this function is result.

The following example shows that the return statement is executed before the final code and only after the final code has been executed.

var count = 0;
function countUp() {
  try {
    return count;
  } finally {
    count++;
  }
}

countUp()
// 0
console.log(count);
// 1

The code above indicates that the count value in the return statement is obtained before the final block of code runs.

Below is a typical scenario of finally block usage.

openFile();

try {
  writeFile(Data);
} catch(e) {
  handleError(e);
} finally {
  closeFile();
}

The above code first opens a file, then writes the file in the try code block. If no error occurs, run the finally code block to close the file. If an error occurs, use the catch code block to process the error first, and then use the finally code block to close the file.

The following example fully reflects the execution order between try...catch...finally.

function f() {
  try {
    console.log(0);
    throw 'bug';
  } catch(e) {
    console.log(1);
    return true; // This sentence would have been deferred until the end of the finally block of code
    console.log(2); // Will not run
  } finally {
    console.log(3);
    return false; // This sentence overrides the previous return
    console.log(4); // Will not run
  }

  console.log(5); // Will not run
}

var result = f();
// 0
// 1
// 3

result
// false

In the code above, the final block of code is executed before the catch block finishes execution.

In the catch code block, the flag that triggers the transition to the final code block is not only a return statement, but also a throw statement.

function f() {
  try {
    throw 'Error!';
  } catch(e) {
    console.log('Internal error caught');
    throw e; // This sentence would have waited until finally was finished
  } finally {
    return false; // Return directly
  }
}

try {
  f();
} catch(e) {
  // Not here
  console.log('caught outer "bogus"');
}

//  Internal error caught

In the above code, once you enter the catch code block, upon encountering a throw statement, you execute the final code block, which has a return false statement, so you go back directly and do not go back to the rest of the catch code block.

Inside the try code block, you can also use the try code block.

try {
  try {
    consle.log('Hello world!'); // Report errors
  }
  finally {
    console.log('Finally');
  }
  console.log('Will I run?');
} catch(error) {
  console.error(error.message);
}
// Finally
// consle is not defined

In the code above, try is also inside try.An inner try error (console misspelled) executes the inner finally block, then throws an error and is caught by the outer catch.

104 original articles were published. 64 were praised. 90,000 visits+
Private letter follow

Posted by seavolvox on Mon, 27 Jan 2020 21:58:28 -0800