引言
在前端开发中,Promise是一种用于处理异步操作的机制,它可以有效地解决回调地狱的问题。然而,当Promise链中发生错误时,如果没有进行适当的处理,这些错误可能会被忽略或导致应用程序崩溃。为了及时发现和解决这些问题,我们需要在前端监控SDK中实现Promise错误的捕获。
window.addEventListener(‘unhandledrejection’, callback)
unhandledrejection
是一个JavaScript中的错误处理机制,用于处理未被捕获的Promise rejection(拒绝)。
当一个Promise被拒绝(rejected)时,如果没有通过catch()或者then()方法的第二个参数来处理这个拒绝,那么就会触发unhandledrejection
事件。
unhandledrejection
事件是一个全局事件,可以通过window对象的unhandledrejection
属性来监听。当这个事件被触发时,可以获取到拒绝的原因(reason)和相关的Promise对象。
通常情况下,我们应该在代码中显式地处理Promise rejection,以避免触发unhandledrejection事件。这可以通过使用catch()方法或者在then()方法中传递第二个参数来实现。这样做可以确保我们能够及时地处理Promise rejection,并避免出现未捕获的错误。
如果没有正确地处理Promise rejection,并且触发了unhandledrejection事件,那么可能会导致应用程序出现未知的错误或者异常行为。因此,在编写JavaScript代码时,我们应该始终注意处理Promise rejection,并确保不会出现未捕获的情况。
window.addEventListener('unhandledrejection', function(event) {
let lastEvent = getLastEvent()
let message
let filename
let lineno = 0
let colno = 0
let stack = ''
let reason = event.reason
if (typeof reason === 'string') {
message = reason
} else if (typeof reason === 'object') {
message = reason.message
if (reason.stack) {
let matchResult = reason.stack.match(/at\s+(.+):(\d+):(\d+)/)
filename = matchResult[1]
lineno = matchResult[2]
colno = matchResult[3]
}
stack = getStackLines(reason.stack)
}
tracker.send({
kind: 'stability', // 稳定性(大类)
type: 'error', // 小类(js error)
errorType: 'promiseError', // JS执行错误
message, // 报错信息
filename, // 报错文件
position: `${lineno}:${colno}`, // 报错位置 行:列
stack,
selector: lastEvent ? getSelector(lastEvent.path) : '' // 最后一个操作的元素
})
}, true)
当发生未处理的 Promise 错误时,浏览器会触发 unhandledrejection
事件,并将错误信息传递给事件处理函数。
在事件处理函数中,首先通过 getLastEvent()
函数获取最后一个用户操作的事件对象。然后定义了一些变量用于存储错误信息,包括 message
、filename
、lineno
、colno
和 stack
。
接下来判断错误原因的类型,如果是字符串类型,则将其赋值给 message
变量;如果是对象类型,则将其 message
属性赋值给 message
变量,并且如果存在 stack
属性,则通过正则表达式匹配出文件名、行号和列号,并分别赋值给对应的变量。
最后调用 tracker.send()
方法发送错误信息到远程服务器。其中包括了一些字段,如 kind
表示稳定性大类,这里是 ‘stability’;type
表示错误类型小类,这里是 ‘error’;errorType
表示 JS 执行错误类型,这里是 ‘promiseError’;还有报错信息、报错文件、报错位置、堆栈信息和最后一个操作元素的选择器等。
上述所用到的getLastEvent、getStackLines、getSelector可看前端监控sdk开发(二)js错误捕获
html代码
<div class="container">
<div class="content">
<input type="button" value="promiseError" onclick="promiseError()" />
</div>
</div>
<script>
function promiseError() {
new Promise(function (resolve, reject) {
window.someVar.error = 'error'
}).then(res => {
console.log(res);
})
}
</script>
报错event数据截图
处理后的数据
{
"title": "前端监控",
"url": "http://127.0.0.1:5500/projects/bug-report/packages/sdk/src/index.html",
"timestamp": 1703151311993,
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"kind": "stability",
"type": "error",
"errorType": "promiseError",
"message": "Cannot set properties of undefined (setting 'error')",
"filename": "http://127.0.0.1:5500/projects/bug-report/packages/sdk/src/index.html",
"position": "52:30",
"stack": "http://127.0.0.1:5500/projects/bug-report/packages/sdk/src/index.html:52:30^new Promise (<anonymous>)^promiseError (http://127.0.0.1:5500/projects/bug-report/packages/sdk/src/index.html:51:7)^HTMLInputElement.onclick (http://127.0.0.1:5500/projects/bug-report/packages/sdk/src/index.html:20:76)",
"selector": ""
}
总结
通过监听unhandledrejection事件,我们可以捕获未被.catch()方法处理的Promise错误;在实际开发中,我们可以根据具体需求和场景选择合适的方式来实现Promise错误的捕获,并将捕获到的错误信息发送到监控服务器进行记录和分析,以提高应用程序的稳定性和用户体验。
原文链接:https://juejin.cn/post/7314947185866473523 作者:俊刚