Others
JavaScript Error Handling
Basic Error Handling
Use try…catch to handle errors that occur while executing code.
try {
const response = await fetch(`/api/users/${userId}`)
return await response.json()
} catch (error) {
console.log(error.message)
}
The catch block receives the thrown error object, allowing you to inspect properties such as message or name.
Creating Custom Errors
Custom error classes make it easier to identify and handle specific types of errors.
class ValidationError extends Error {
constructor(message) {
super(message)
this.name = 'ValidationError'
}
}
class NetworkError extends Error {
constructor(message, statusCode) {
super(message)
this.name = 'NetworkError'
this.statusCode = statusCode
}
}
Usage:
throw new ValidationError('Invalid email')
A Better Custom Error Pattern
Instead of manually setting the name property in every error class, create a common base class.
class AppError extends Error {
constructor(message, options) {
super(message, options)
this.name = this.constructor.name
}
}
class ValidationError extends AppError {}
class DatabaseError extends AppError {}
class NetworkError extends AppError {}
Now every subclass automatically gets the correct error name.
throw new ValidationError('Invalid email')
// error.name === "ValidationError"
Handling Different Error Types
Use instanceof to handle different errors appropriately.
try {
await saveUser(userData)
} catch (error) {
if (error instanceof ValidationError) {
// Show validation message to the user
showFieldErrors(error.fields)
} else if (error instanceof NetworkError) {
// Network issue - maybe retry
showRetryButton()
} else {
// Unknown error
console.error('Unexpected error:', error)
showGenericError()
}
}
Always Check response.ok with fetch
- A common mistake is assuming that
fetch()throws an error for HTTP status codes like 404 or 500. - It doesn't.
fetch()only throws for network-related failures. For HTTP errors, you must checkresponse.okyourself.
- Incorrect
try {
const response = await fetch('/api/users/999')
const user = await response.json()
} catch (error) {
// Only catches network errors
}
- Correct
try {
const response = await fetch('/api/users/999')
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`)
}
const user = await response.json()
} catch (error) {
// Catches both network and HTTP errors
console.error('Request failed:', error.message)
}
JavaScript Regular Expressions (RegExp)
- Regular expressions (RegExp) are patterns used to search, validate, extract, and replace text.
test() Vs match()
These are two of the most commonly used regular expression methods.
test()- Returns a boolean indicating whether the pattern matches.
const emailPattern = /\S+@\S+\.\S+/
console.log(emailPattern.test('user@example.com')) // true
console.log(emailPattern.test('userexample.com')) // false
match()- Returns an array containing the matched text (or
nullif no match is found). - Using the
g(global) flag returns all matches instead of only the first.
- Returns an array containing the matched text (or
const text = 'Order IDs: 123, 456, 789'
console.log(text.match(/\d+/g))
// ["123", "456", "789"]
search()
- Returns the index where the first match starts.
- If no match is found, it returns
-1.
const text = 'Hello World'
console.log(text.search(/World/)) // 6
console.log(text.search(/xyz/)) // -1
replace()
- Replace matching text with another value.
- Using the
gflag replaces all occurrences.
console.log('hello world'.replace(/o/g, '0'))
// "hell0 w0rld"
split()
- Regular expressions can also be used with
split().
// The pattern removes optional whitespace around commas.
const items = 'a, b,c , d'.split(/\s*,\s*/)
console.log(items)
// ["a", "b", "c", "d"]
Named Capture Groups
- Named capture groups make matched values easier to access.
- Use the following syntax:
(?<name>pattern)
- Example:
const datePattern = /(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/
const match = '12-25-2024'.match(datePattern)
console.log(match.groups.month) // "12"
console.log(match.groups.day) // "25"
console.log(match.groups.year) // "2024"
Greedy Vs Lazy Matching
- By default, quantifiers are greedy. They match as much text as possible.
- Adding
?makes a quantifier lazy, meaning it matches as little text as possible. - Example:
const html = '<div>Hello</div><div>World</div>'
Greedy
Matches everything between the first <div> and the last </div>.
console.log(html.match(/<div>.*<\/div>/)[0])
// "<div>Hello</div><div>World</div>"
Lazy
Stops at the first closing </div>.
console.log(html.match(/<div>.*?<\/div>/)[0])
// "<div>Hello</div>"