During development, our goal is to 0error,0warning
.
But there are many factors that are beyond our control. In order to avoid errors in a certain piece of code and affect the operation of other modules or the overall code, we often use modules try-catch
to actively catch some exceptions or errors.
For example, after we get the parameters url
in and JSON
parse them, we need to try-catch
wrap them here, because we cannot guarantee that the parameters we get can be parsed normally:
const user= getQueryString('user');
if (user) {
try {
const {
id, username} = JSON.parse(user);
console.log(id, username);
} catch (err) {
console.error(err);
}
}
In the process of copying the link, the user may intentionally or unintentionally copy incompletely, resulting in incomplete parameters, which JSON.parse
cannot be parsed json string
. To avoid JSON
parsing , we can try-catch
include it with .
1. What errors cannot be caught by try-catch
We often use try-catch
modules to actively catch some exceptions or errors, so as to prevent the code of this block from affecting the operation of other modules or the overall code. But in some cases, try-catch
exceptions in the code cannot be caught!
1. Cross domain error
When we use the xhr request interface, if the interface does not support cross-domain, the browser will prompt an error in the console:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>trycatch演示</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script>
</head>
<body>
<button onclick="cli()">点我</button>
<script>
function cli() {
try {
$.get('http://www.baidu.com', function success(data) {
console.log(data)
})
} catch (e) {
console.log(e)
}
}
</script>
</body>
</html>
Access to XMLHttpRequest at 'https://www.baidu.com/' (redirected from 'http://www.baidu.com/') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
From the picture, we can see that a cross-domain error occurred when requesting the interface, but it did not enter the catch. Through the monitoring of xhr.onerror, we can know that the xhr request has generated a request error.
2. Asynchronous errors
If an asynchronous module try
in , generates an error, catch
it cannot be caught, for example:
// setTimeout中的错误
try {
setTimeout(function () {
throw new Error('error in setTimeout'); // 200ms后会把异常抛出到全局
}, 200);
} catch (err) {
console.error('catch error', err); // 不会执行
}
// Promise中的错误
try {
Promise.resolve().then(() => {
throw new Error('error in Promise.then');
});
} catch (err) {
console.error('catch error', err);
As can be seen from the running results, neither of these two codes enters catch
the module .
Why didn't it enter the catch module?
When an asynchronous function throws an exception, for a macro task, the function has been pushed onto the stack when the function is executed, and it is not on the stack where the try-catch is located at this time, so the try-catch cannot catch the error. For microtasks, such as promise, the exception of the promise's constructor can only be caught by the built-in reject, that is, the .catch function.
The answer to catching asynchronous errors
is to try-catch
put inside the asynchronous code.
1. Put try-catch inside setTimeout
// 将try-catch放到setTimeout内部
setTimeout(() => {
try {
throw new Error('error in setTimeout');
} catch (err) {
console.error('catch error', err);
}
}, 200);
2. Put try-catch inside then
// 将try-catch放到then内部
Promise.resolve().then(() => {
try {
throw new Error('error in Promise.then');
} catch (err) {
console.error('catch error', err);
}
});
3. Use the catch that comes with Promse to catch exceptions
// 使用Promse自带的catch捕获异常
Promise.resolve()
.then(() => {
throw new Error('error in Promise.then');
})
.catch((err) => {
console.error('Promise.catch error', err);
});
Promise
A great advantage is that it has its own exception capture method catch()
, then()
which will automatically enter catch()
the method when an error occurs in the method and the code cannot run. Therefore, it is recommended to write Promise
when catch()
, otherwise uncaught exceptions will bubble up to the global.
3. How to catch the exception of async-await
await
Can be .catch()
used simultaneously with . try/catch
Can catch all exceptions, only errors .catch
in asynchronous methodsreject
In other words, if you only want to capture reject
errors in asynchronous methods, you can capture them await
while using them ..catch()
But exceptions other than reject cannot be caught.
As shown below:
1. At the same time, the exception was caught by using reject
:
const foo=()=>{
return new Promise((resolve, reject) => {
throw new Error('throw 错误')
});
}
await foo().catch(e=>{
console.log('捕获到了:'+e)});
2. reject
If the exception cannot be caught, report an error directly:
(In this case, you need to use try/catch to capture and process)
const foo=()=>{
throw new Error('throw 错误');
return new Promise((resolve, reject) => {
resolve('resolve 错误')
});
}
await foo().catch(e=>{
console.log('捕获到了:'+e)});
But after this kind of exception is caught, catch()
the method cannot catch the exception, and it will no longer continue to bubble to the outer layer. The correct approach is that errors generated by the underlying modules should be thrown directly to the business layer, allowing the business layer to decide how to deal with the error instead of swallowing it directly.
4. Multi-layer try-catch
try-catch
When there are multiple layers , it will catch()
be captured by the innermost method, and then it will no longer bubble to the outer layer:
try {
try {
throw new Error('error');
} catch (err) {
console.error('内层的catch', err); // 内层的catch Error: error
}
} catch (err) {
console.error('最外层的catch', error);
}
The type of error that occurs in js.
Before knowing how to use it try-catch
, let's first understand what are the native error types js
in .
js
There are 6 types of errors that may occur when the code is running:
- syntax error(
SyntaxError
); - typeError(
TypeError
); - RangeError(
RangeError
); eval
error(EvalError
);- referenceError(
ReferenceError
); URI
error(URIError
);
These error types are all inherited from the Error
class.
1. Syntax error ( SyntaxError
)
Grammatical errors are usually caused by developers writing code statements during the development process, which cannot be parsed by the browser:
const a=;
Error message:
VM202:1 Uncaught SyntaxError: Unexpected token ';'
2. Type error ( TypeError
);
Type errors usually appear in two situations:
- The operator is used on an inappropriate type variable, such as using
concat
the operator ; - The variable of the operation encountered an unexpected
null
orundefined
value:
const obj = {
};
obj.concat([1]);
error message
VM211:2 Uncaught TypeError: obj.concat is not a function
at <anonymous>:2:5
const a = null;
a.nickname; //VM218:2 Uncaught TypeError: Cannot read properties of null (reading 'nickname')at <anonymous>:2:3
When writing some methods for other modules to call, when checking that the parameter input is empty or null
empty , TypeError
an error can be thrown.
3. Range error ( RangeError
);
This error is usually because the parameters passed in are beyond the specified range. For example, toFixed()
the method can accept values within 0-100
the range , and when this range is exceeded, this error will be thrown.
Math.PI.toFixed(105); // Uncaught RangeError: toFixed() digits argument must be between 0 and 100
4. eval
Error ( EvalError
);
This kind of error is generally rarely encountered, because when using eval
the operation , even improper errors will throw other types of errors.
new eval(); // Uncaught TypeError: eval is not a constructor
eval = 1234; // 正确执行
5. Reference error ( ReferenceError
);
A reference error means that the master and apprentice are accessing an undeclared variable:
console.log(nick); // Uncaught ReferenceError: nick is not defined
6. URI
Error ( URIError
);
This error is usually an error thrown by some operation uri functions, mainly including: encodeURI(), decodeURI(), encodeURIComponent(), decodeURIComponent(), escape(), unescape()
.
decodeURIComponent('%'); // Uncaught URIError: URI malformed
decodeURIComponent('%23'); // # 正确执行
custom error type
For a slightly larger module, we want to customize some error types. Through these error types, we can see that an error is thrown by a certain module. How should I write it?
Our custom error type should also be inherited from the class Error
, which is very simple to implement:
class FingerError extends Error {
constructor(message) {
super(message);
this.name = 'FingerError'; // 该错误的名称
Error.captureStackTrace(this, this.constructor); // 获取错误堆栈的信息
}
}
const err = new FingerError('get name error');
console.error(err); // FingerError: get name error
err instanceof FingerError; // true
Summarize
There are still many ways to generate errors in the front end, and we should pay attention to avoiding these errors at ordinary times. Next, we can also analyze from the perspective of error monitoring, how to monitor the errors and error types that appear on the page.