fan*_*ncy 10 html javascript reactjs
我想在我的 React 应用程序中全局捕获错误。
但是每次错误被捕获/转发两次到我注册的函数。
示例代码:
window.onerror = (msg, url, lineNo, columnNo, error) => {
console.log(msg)
alert(msg)
}
class TodoApp extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<button onClick={(e)=>{
console.log("clicked")
null.bla
}}>
Create an error
</button>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
Run Code Online (Sandbox Code Playgroud)
这是一个 JS 小提琴:https : //jsfiddle.net/dmxur0rc/4/
控制台只显示一个“点击”日志,因此触发两次的不是按钮,而是错误事件。
小智 6
我找到了一个基本的解决方案,它应该适用于所有场景。
事实证明,该对象在所有调用中都是相同的,您可以设置一些内容以完全匹配它们,或者您可以将自定义属性附加到错误对象...
诚然,这可能仅适用于 window.addEventListener('error', function...),因为您将获得真正的错误对象作为参数,而不是 window.onerror = function... 获取数据部分,例如作为消息和行号,而不是真正的错误。
这基本上是我使用它的方式:
window.addEventListener('error', function (event) {
if (event.error.hasBeenCaught !== undefined){
return false
}
event.error.hasBeenCaught = true
// ... your useful code here
})Run Code Online (Sandbox Code Playgroud)
如果两次调用它时出现相同的错误,它将在获取有用代码之前退出,每个错误只执行一次有用代码。
您需要true从错误处理程序返回,否则将触发默认错误处理程序:
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror
当函数返回 true 时,这会阻止触发默认事件处理程序。
另请注意,其他错误处理程序可能通过addEventHandler.
正如其他答案中提到的,问题出在 DEV 模式下的 React 中。在此模式下,它会重新抛出所有异常以“改善调试体验”。
正常的 JS 错误(例如,来自事件处理程序,如问题中所示)。
这些由 React 的发送window.onerror 两次invokeGuardedCallbackDev。
期间发生的JS错误,并且组件树中render没有React的错误边界。
与场景1相同。
期间发生的 JS 错误,并且组件树中的某处render存在错误边界。
这些被发送到一次window.onerror ,invokeGuardedCallbackDev但也被错误边界的捕获。 componentDidCatch
承诺内的 JS 错误未得到处理。
这些不是发送到window.onerror,而是发送到window.onunhandledrejection。而且这种情况只会发生一次,所以这没有问题。
window.addEventListener('error', function (event) {
const { error } = event;
// Skip the first error, it is always irrelevant in the DEV mode.
if (error.stack?.indexOf('invokeGuardedCallbackDev') >= 0 && !error.alreadySeen) {
error.alreadySeen = true;
event.preventDefault();
return;
}
// Normal error handling.
}, { capture: true });
Run Code Online (Sandbox Code Playgroud)