Preface
I don’t know if my friends have such experience. Everything is normal when debugging a local development project. Once it is released online, various strange problems will occur. The reasons are also various. The environment variables are different, the host environment is different, and the interface returns. Different data formats, code logic issues, etc.
Some errors can be found in the development and testing process, and some errors will not be found until they arrive online. At this time, waiting for user feedback is too passive. Therefore, a monitoring system that collects and captures code errors is particularly important. .
The purpose of this series of articles is not to allow everyone to build a front-end code monitoring system immediately. It is to introduce the common ways of capturing code errors in the browser environment, and to create a front-end plug-in that collects code errors in a well-known way. Finally Then briefly introduce how to quickly locate the error after collecting the error information.
Common error types
Before starting our subject, we first need to understand the common types of errors.
Code writing error
This type of error is the easiest to eliminate, we often only need to use the editor's automatic detection, or eslint
tslint
and other third-party tools, in the development stage can be resolved.
Of course, if some students use a text editor to write code, please download a vscode to experience a better coding environment while accepting my knees.
function foo()
cont bar = "string"
Code execution error
This can be said to be the most encountered in normal development. For example, in the following example, I believe that many students use vue
or react
to obtain list data through the interface. If the back-end students do not return []
for empty data, they return If you use null
or undefined
, there will be problems with the front-end display.
Some students will also say that ts Dafa is good, and the interface definition is fragrant (but in fact, this does not solve the problem of inconsistent interface return), and if you encounter a situation where the any
. .
undefined.map((item) => console.log(item));
Other types of errors, such as the use of an undefined variable, can be avoided in the development phase.
console.log(helloWorld);
Asynchronous code reject
I do not know little friends using promise
when there is no catch
reject
habits, I believe most people are there except me (against their will), that for not actively catch
of reject
How should we caught and handled?
const promise = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("promise reject"));
}, 1000);
});
// 未使用 catch 捕获错误
promise().then(console.log);
Resource loading error
Resource loading error is also a bald problem, if it is only image
it is okay, if it is important js
, css
resource loading error. . .
<!-- 你说这个资源能加载?嗯?你有问题,小老弟 -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
Catch code errors
vue
. Some students may say, "Oh, I usually use react
. I can't make mistakes in such a simple scenario."
Shhh, hold back your words, the frameworks throw errors in those simple ways.
In addition, the following content has detailed code and comments. clone
code locally. For specific instructions, see README.md
project branch.
git clone -b demo/catch-code-error https://github.com/jsjzh/tiny-codes.git
Code execution error
In peacetime, when writing code, if you encounter may perform error logic, we usually use try catch
, wrapped, and then do the treatment alone, but for some unexpected errors, such as the above interfaces return; there If an error occurs in the asynchronous code, the error try catch
cannot be caught by . At this time, window.onerror
will come in handy.
We can understand this way, try catch
used to capture expected errors, and window.onerror
used to capture unexpected errors, that is, the bottom line strategy.
/**
* message {String}: 错误信息
* fileName {String}: 发生错误的文件
* col {Number}: 错误代码的行
* row {Number}: 错误代码的列
* error {Error}: Error 对象
*/
window.onerror = (message, fileName, col, row, error) => {
console.log("message: ", message);
console.log("fileName: ", fileName);
console.log("col: ", col);
console.log("row: ", row);
console.log("error.name: ", error.name);
console.log("error.message: ", error.message);
console.log("error: ", error);
};
Active try catch
In the code below, we took the initiative to try catch
an error in 0607aff028e1c6, which means that we know that there may be errors in the logic of try
catch
. In fact, this error situation may not need to be reported because we have already done the corresponding error handling.
ps: if it thinks still need to report an error, you cancatch
increase paragraphthrow error
logic, so that errors can be thrown, iswindow.onerror
capture.
// 同步执行代码,通过 try catch 可以捕获错误
try {
console.log(helloWorld);
} catch (error) {
// 在这里做一些自定义处理
// ...
// 若做了自定义处理后,仍旧需要上报错误,增加 throw error
// throw error;
}
Unexpected error
In the following situation, we did not expect an error to be reported, and the error will be directly captured window.onerror
ps: Here, theprocess
object is accessed in the browser environment, which is a global variable only available in thenode
// 未使用 try catch 捕获错误
// 说明我们未预料到这段代码可能出错
console.log(process);
Asynchronous code execution error
If there is a code execution error in the asynchronous logic code, we try catch
. At this time, there are two ways. The first is to wrap the asynchronously executed function with try catch
. We will not give an example of this. The second method The error is captured window.onerror
const promise = () =>
new Promise(() => {
setTimeout(() => {
console.log(helloWorld);
}, 1000);
});
try {
promise().then();
} catch (error) {
// 无法捕获到错误 error
console.log("can't catch error");
}
As you can see in the picture above, the error was captured window.onerror
Asynchronous code reject
Saying asynchronous code reject
ago, we have to have a consensus, promise
of catch
not be captured code execution error, only through reject()
of throwing an exception, will only be promise.catch
captured, what does that mean? Look at the code below.
const promise = () =>
new Promise(() => {
setTimeout(() => {
console.log(helloWorld);
}, 1000);
});
promise()
.then()
// 无法捕获到 helloWorld 的错误
.catch(() => {
console.log("can't catch error");
});
So what error can promise
of catch
The answer is reject
, as follows.
const promise2 = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
// 通过 reject 抛出错误
reject(new Error("promise reject"));
}, 1000);
});
promise2()
.then()
.catch((error) => {
// 能够捕获到错误
console.log("error.name: ", error.name);
console.log("error.message: ", error.message);
console.log("error: ", error);
});
The above content is just to reach a consensus between us. Next, let's talk about how to capture catch
that is reject
and pass window.onunhandledrejection
.
ps: One thing needs to be reminded. For custom errors thrown, try to usenew Error(...)
, so that we can not only get the complete error information, but also the file name, error line and error column, which is the so-called stack information .ps2: If it is
promise.catch
captured byreject
, it will not bewindow.onunhandledrejection
. If you still want to report this error, you can usethrow error
, which will be capturedwindow.onerror
window.onunhandledrejection = (promiseRejectEvent) => {
// Error 对象,由 reject(new Error()) 生成
const reason = promiseRejectEvent.reason;
if (reason) {
console.log("reason.name: ", reason.name);
console.log("reason.message: ", reason.message);
console.log("reason.stack: ", reason.stack);
}
};
const promise2 = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
// 通过 reject 抛出错误
reject(new Error("promise reject"));
}, 1000);
});
// 未使用 catch,错误将被 window.onunhandledrejection 捕获
promise2().then();
Resource loading error
Regarding resource loading errors, whether it is js
, css
, image
, we can monitor and capture errors window.addEventListener("error")
However, the resource loading error caused by background-image: url(./error.png)
new Image().src = "./error.png"
cannot be captured by this method.
ps: If a friend knows any way to catch these loading errors, please tell me that I will update it in the article after my self-test is successful.
window.addEventListener(
"error",
(sourceErrorEvent) => {
const targetElement =
sourceErrorEvent.target || sourceErrorEvent.srcElement;
const url = targetElement.src || targetElement.href;
console.log("sourceError: ", url);
},
true
);
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="./error.js"></script>
<link rel="stylesheet" href="./error.css" />
<img src="./error.png" />
Unexpected little problem
I believe that with the above three solutions, we have been able to capture most of the errors. However, when debugging, we found that when the loaded js
resource is cross-domain, window.onerror
will only collect error information Script error.
, as shown in the figure below.
Why is this happening? Of course it is the strategy of the browser. . . But we also have corresponding solutions.
ps: For the html
tag resources, please refer to MDN's crossOrigin attribute description.
Back to the question, we only need to do two things, first:
Add a crossOrigin="anonymous"
attribute to js
resource loaded across domains
<script src="http://127.0.0.1:7002/index.js" crossorigin="anonymous"></script>
second:
Ensure that the cross-domain resource server sets the Access-Control-Allow-Origin: hosts
header, and your browser sends Origin: host
in its list. If it is troublesome, the server can directly set Access-Control-Allow-Origin: *
.
ps: In fact, it is not recommended to set it to*
. If you usecookie
, this will causecookie
not work properly. You need to set some other headers to makecookie
take effect.
Of course, if the resources are configured in a unified CDN, then the header can be configured separately for the static resource server.ps2: You don’t need to actively add the
Origin
header, this is the browser’s spontaneous behavior
# Response Header
...
Access-Control-Allow-Origin: http://127.0.0.1:7001
...
# Request Header
...
Origin: http://127.0.0.1:7001
...
As above, we can get the detailed information of the error.
Just a little emphasis, the above examples can be found in the following examples.
git clone -b demo/catch-code-error https://github.com/jsjzh/tiny-codes.git
Afterword
At this point, the correct posture for catching code errors (1) is over. When writing the article, I learned a lot of points that I would not usually pay attention to. I also have some insights about the magical front-end code monitoring system.
Of course, some students have to say, isn’t sentry fragrant? Why take time and effort to mess around with yourself? Regarding this point, I think that if we are just to solve the problem, it is naturally best to use a ready-made solution. But if you don't toss, what is the difference with salted fish? (Escape
There are two more chapters following the article. In the second chapter, I will build a plug-in that collects front-end error messages. In the third chapter, I will provide some immature solutions for how to locate problems after code compression that is very common now.
In addition, the writing is poor and the plan is naive. If the judges have any comments or suggestions, please leave a message in the comment area and we will discuss and discuss together.
Footer
Code is life, and I am happy with it.
Technology is constantly changing
Mind is always online
The front end is long
See you next timeby --- Crotch Trio
I am here gayhub@jsjzh welcome everyone to come and play with me.
Welcome friends to add me directly, pull you into the group and do things together, remember to note where you saw the article.
ps: If the picture is invalid, you can add me wechat: kimimi_king
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。