Troubleshooting Flashcards

1
Q

Explain the two main types of error that you’ll come across in JavaScript

A
  • Syntax errors: These are spelling errors in your code that actually cause the program not to run at all, or stop working part way through — you will usually be provided with some error messages too. These are usually okay to fix, as long as you are familiar with the right tools and know what the error messages mean!
  • Logic errors: These are errors where the syntax is actually correct but the code is not what you intended it to be, meaning that program runs successfully but gives incorrect results. These are often harder to fix than syntax errors, as there usually isn’t an error message to direct you to the source of the error.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Explain Error object

A

Error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions.

Runtime errors result in new Error objects being created and thrown.

Instance properties

These properties are defined on Error.prototype and shared by all Error instances.

  • Error.prototype.constructor - The constructor function that created the instance object. For Error instances, the initial value is the Error constructor.
  • Error.prototype.name - Represents the name for the type of error. For Error.prototype.name, the initial value is "Error". Subclasses like TypeError and SyntaxError provide their own name properties.
  • cause - Error cause indicating the reason why the current error is thrown — usually another caught error. For user-created Error objects, this is the value provided as the cause property of the constructor’s second argument.
  • message - Error message. For user-created Error objects, this is the string provided as the constructor’s first argument.

Throwing an Error

try {
  throw new Error("Whoops!");
} catch (e) {
  console.error(`${e.name}: ${e.message}`);
}

Handling an Error

try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.error(`${e.name}: ${e.message}`);
  } else if (e instanceof RangeError) {
    console.error(`${e.name}: ${e.message}`);
  }
  // etc.
  else {
    // If none of our cases matched leave the Error unhandled
    throw e;
  }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Explain SyntaxError built-in error type

A

The SyntaxError object represents an error when trying to interpret syntactically invalid code. It is thrown when the JavaScript engine encounters tokens or token order that does not conform to the syntax of the language when parsing code.

SyntaxError is a Serializable object, so it can be cloned with structuredClone() or copied between Workers using postMessage().

It is a subclass of Error.
Example:

try {
  eval("hoo bar");
} catch (e) {
  console.log(e instanceof SyntaxError); // true
  console.log(e.message);
  console.log(e.name); // "SyntaxError"
  console.log(e.stack); // Stack of the error
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Explain RangeError built-in error type

A

The RangeError object indicates an error when a value is not in the set or range of allowed values.

A RangeError is thrown when trying to pass a value as an argument to a function that does not allow a range that includes the value.

This can be encountered when:

  • passing a value that is not one of the allowed string values to String.prototype.normalize(), or
  • when attempting to create an array of an illegal length with the Array constructor, or
  • when passing bad values to the numeric methods Number.prototype.toExponential(), Number.prototype.toFixed() or Number.prototype.toPrecision().

RangeError is a Serializable object, so it can be cloned with structuredClone() or copied between Workers using postMessage().

It is a subclass of Error.

Example:

function check(n) {
  if (!(n >= -500 && n <= 500)) {
    throw new RangeError("The argument must be between -500 and 500.");
  }
}

try {
  check(2000);
} catch (error) {
  if (error instanceof RangeError) {
    // Handle the error
  }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Explain ReferenceError built-in error type

A

The ReferenceError object represents an error when a variable that doesn’t exist (or hasn’t yet been initialized) in the current scope is referenced.

ReferenceError is a Serializable object, so it can be cloned with structuredClone() or copied between Workers using postMessage().

It is a subclass of Error.

Example:

try {
  let a = undefinedVariable;
} catch (e) {
  console.log(e instanceof ReferenceError); // true
  console.log(e.message); // "undefinedVariable is not defined"
  console.log(e.name); // "ReferenceError"
  console.log(e.stack); // Stack of the error
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Explain TypeError built-in error type

A

The TypeError object represents an error when an operation could not be performed, typically (but not exclusively) when a value is not of the expected type.

A TypeError may be thrown when:

  • an operand or argument passed to a function is incompatible with the type expected by that operator or function; or
  • when attempting to modify a value that cannot be changed; or
  • when attempting to use a value in an inappropriate way.

TypeError is a Serializable object, so it can be cloned with structuredClone() or copied between Workers using postMessage().

It is a subclass of Error.

Examples

Catching a TypeError

try {
  null.f();
} catch (e) {
  console.log(e instanceof TypeError); // true
  console.log(e.message); // "null has no properties"
  console.log(e.name); // "TypeError"
  console.log(e.stack); // Stack of the error
}

Creating a TypeError

try {
  throw new TypeError("Hello");
} catch (e) {
  console.log(e instanceof TypeError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "TypeError"
  console.log(e.stack); // Stack of the error
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Explain URIError built-in error type

A

The URIError object represents an error when a global URI handling function was used in a wrong way.

URIError is a Serializable object, so it can be cloned with structuredClone() or copied between Workers using postMessage().

It is a subclass of Error.

Examples
Catching an URIError

try {
  decodeURIComponent("%");
} catch (e) {
  console.log(e instanceof URIError); // true
  console.log(e.message); // "malformed URI sequence"
  console.log(e.name); // "URIError"
  console.log(e.stack); // Stack of the error
}

Creating an URIError

try {
  throw new URIError("Hello");
} catch (e) {
  console.log(e instanceof URIError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "URIError"
  console.log(e.stack); // Stack of the error
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Explain AgregateError built-in error type

A

The AggregateError object represents an error when several errors need to be wrapped in a single error. It is thrown when multiple errors need to be reported by an operation, for example by Promise.any(), when all promises passed to it reject.

Instance properties

Also inherits instance properties from its parent Error.

These properties are defined on AggregateError.prototype and shared by all AggregateError instances.

  • AggregateError.prototype.constructor - The constructor function that created the instance object. For AggregateError instances, the initial value is the AggregateError constructor.
  • AggregateError.prototype.name - Represents the name for the type of error. For AggregateError.prototype.name, the initial value is "AggregateError".

These properties are own properties of each AggregateError instance.

  • errors - An array representing the errors that were aggregated.

Examples

Catching an AggregateError

Promise.any([Promise.reject(new Error("some error"))]).catch((e) => {
  console.log(e instanceof AggregateError); // true
  console.log(e.message); // "All Promises rejected"
  console.log(e.name); // "AggregateError"
  console.log(e.errors); // [ Error: "some error" ]
});

Creating an AggregateError

try {
  throw new AggregateError([new Error("some error")], "Hello");
} catch (e) {
  console.log(e instanceof AggregateError); // true
  console.log(e.message); // "Hello"
  console.log(e.name); // "AggregateError"
  console.log(e.errors); // [ Error: "some error" ]
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Explain how to create custom error types

A

You might want to define your own error types deriving from Error to be able to throw new MyError() and use instanceof MyError to check the kind of error in the exception handler. This results in cleaner and more consistent error handling code.

NOTE: Custom error types can also use the cause property, provided the subclasses’ constructor passes the options parameter when calling super(). The Error() base class constructor will read options.cause and define the cause property on the new error instance.

Example:

class CustomError extends Error {
  constructor(foo = "bar", ...params) {
    // Pass remaining arguments (including vendor specific ones) to parent constructor
    super(...params);

    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CustomError);
    }

    this.name = "CustomError";
    // Custom debugging information
    this.foo = foo;
    this.date = new Date();
  }
}

try {
  throw new CustomError("baz", "bazMessage");
} catch (e) {
  console.error(e.name); // CustomError
  console.error(e.foo); // baz
  console.error(e.message); // bazMessage
  console.error(e.stack); // stacktrace
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Explain Error:cause data property

A

The cause data property of an Error instance indicates the specific original cause of the error.

It is used when catching and re-throwing an error with a more-specific or useful error message in order to still have access to the original error.

The value of cause can be of any type. You should not make assumptions that the error you caught has an Error as its cause, in the same way that you cannot be sure the variable bound in the catch statement is an Error either.

Example
Rethrowing an error with a cause
It is sometimes useful to catch an error and re-throw it with a new message. In this case you should pass the original error into the constructor for the new Error, as shown.

try {
  connectToDatabase();
} catch (err) {
  throw new Error("Connecting to database failed.", { cause: err });
}

Providing structured data as the error cause
Error messages written for human consumption may be inappropriate for machine parsing — since they’re subject to rewording or punctuation changes that may break any existing parsing written to consume them. So when throwing an error from a function, as an alternative to a human-readable error message, you can instead provide the cause as structured data, for machine parsing.

function makeRSA(p, q) {
  if (!Number.isInteger(p) || !Number.isInteger(q)) {
    throw new Error("RSA key generation requires integer inputs.", {
      cause: { code: "NonInteger", values: [p, q] },
    });
  }
  if (!areCoprime(p, q)) {
    throw new Error("RSA key generation requires two co-prime integers.", {
      cause: { code: "NonCoprime", values: [p, q] },
    });
  }
  // rsa algorithm…
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the best way to perform selective catching on a try catch?

A

JavaScript doesn’t provide direct support for selectively catching exceptions: either you catch them all or you don’t catch any.

To catch a specific kind of exception. We have to do a check in the catch block. One of the best ways to do so is with the instanceof operaror.

Example

class InputError extends Error {}

function promptDirection(question) {
   if result = prompt(question);
	 if (result.toLowerCase() == "left") return "L";
	 if (result.toLowerCase() == "right") return "R";
	 throw new InputError("Invalid direction: " + result);
}

try {
  let dir = promptDirection("Where?");
	console.log("You chose ", dir);
	break;
} catch (e) {
  if (e instanceof InputError) {
    console.log("not a valid direction. Try again.");
	} else {
	  throw e;
	}
}

Haverbeke, Marijn. “Selective Catching.” In Eloquent JavaScript: A Modern Introduction to Programming, 3rd ed., 138. No Starch Press, 2022.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly