JavaScript 异常处理

Posted

技术标签:

【中文标题】JavaScript 异常处理【英文标题】:JavaScript Exception Handling 【发布时间】:2010-09-17 08:50:17 【问题描述】:

捕捉 javascript 中抛出的所有异常的最佳技术是什么?

显然,最好的技术是使用 try...catch。但是对于异步回调等等,这可能会变得很棘手。

我知道 IE 和 Gecko 浏览器支持 window.onerror,但是 Opera 和 Safari 呢?

这里有一堆测试用例,我希望有一个集中的异常处理解决方案:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw 
    myMessage: "stuff",
    customProperty: 5,
    anArray: [1, 2, 3]
;
// ErrorHandler-Test5
try 
    var test2 = null;
    test2.arg = 5;
 catch(e) 
    ErrorHandler.handleError(e);

// ErrorHandler-Test6
try 
    throw (new Error("Goodbye"));
 catch(e) 
    ErrorHandler.handleError(e);

// ErrorHandler-Test7
try 
    throw "Goodbye again";
 catch(e) 
    ErrorHandler.handleError(e);

// ErrorHandler-Test8
try 
    throw 
        myMessage: "stuff",
        customProperty: 5,
        anArray: [1, 2, 3]
    ;
 catch(e) 
    ErrorHandler.handleError(e);

如果您想到任何其他测试用例,请提及它们。其中一些案例提到了 ErrorHandler.handleError 方法。这只是使用 try...catch 时的建议准则。

【问题讨论】:

只是因为很明显你没有注意到我的回答中的 cmets:当它读作一个问题时,你似乎对我的“问题中陈述”投了反对票:“但是 Opera 和 Safari 呢? "我专门回答了这里提出的一个问题。什么鬼? 在 WebKit 中,window.onerror 的缺失自 2003 以来一直是个问题,但它看起来像是 finally getting resolved。当然,Opera 还是会固执己见。 仅供参考 window.onerror 工作正常 - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60 不确定为什么关闭。投票决定重新开放。 同意,这是一个有用的问题。我唯一能想到的是 casperOne 担心这会变成某种浏览器战争讨论? 【参考方案1】:

如果您使用像 jQuery 这样的库来分配所有事件处理程序,您可以结合使用 window.onerror 并包装 jQuery 事件处理程序代码和带有错误处理函数的就绪函数(请参阅:JavaScript Error Tracking: Why window.onerror Is Not Enough )。

window.onerror:捕获 IE 中的所有错误(以及 Firefox 中的大多数错误),但在 Safari 和 Opera 中不执行任何操作。 jQuery 事件处理程序:捕获所有浏览器中的 jQuery 事件错误。 jQuery 就绪函数:捕获所有浏览器中的初始化错误。

【讨论】:

我已经阅读了没有提供任何解决方案的文章。我不使用 jQuery,但我担心你在暗示什么。你是说 jQuery 吃异常?!还是它们仅提供日志记录功能(仅在我最初的问题得到回答后才有用)? jQuery 对异常没有做任何特别的事情。但是,如果您使用 jQuery 添加所有事件,它会为您提供一个单一的位置来添加您的 try catch 语句和错误处理代码,如我的答案中的第二个链接中所述。 提供的链接已移动:blogs.cozi.com/tech/2008/04/… 这仍然是真的吗?我刚刚在 Safari + Chrome 上尝试了正常的onerror 处理方法,似乎工作正常。 你给出的为什么“这还不够”的链接是相当老的信息,现在不是这样。【参考方案2】:

WebKit(Safari、Chrome 等)现在似乎支持 onerror

原帖:据我所知,WebKit/Safari 不支持onerror 事件。真是太可惜了。

【讨论】:

呃,不是的。在问题中被问到:“但是 Opera 和 Safari 呢?” 如题,我专门回答了问题帖中提出的一个问题。 我认为他的意思是“关于 Opera 和 Safari [没有 window.onerror] [我该怎么做]?” @nickf,也许是这样,但如果是这样的话,它的措辞非常糟糕,我的解释最多是可以理解的,最多是最有可能的。人们对我的回答投反对票是一个非常糟糕的理由,特别是考虑到问题没有 说明,其他读者可能会从肯定或否定的陈述中受益。 Chrome 现在似乎支持它了。【参考方案3】:

实际上,jquery 方法还不错。见:

http://docs.jquery.com/Events/error#fn

和:

$(window).error(function(msg, url, line)
  $.post("js_error_log.php",  msg: msg, url: url, line: line );
);

【讨论】:

对于现在发现此问题的任何人 - jquery 实际上建议不要将事件绑定到 window.error 事件 - 请参阅上面的文档链接。提取:不应将 jQuery 错误事件处理程序附加到窗口对象。 [...] 改用 window.onerror。 ofc 不应该这样绑定,不合逻辑!进行此投标时可能会发生许多错误(如果甚至成功...)【参考方案4】:

使用您自己的异常处理程序捕获所有异常并使用 instanceof。

$("inuput").live(
    click : function (event) 
        try 
            if (somethingGoesWrong) 
                throw new MyException();
            
         catch (Exception) 
            new MyExceptionHandler(Exception);
        

    
);

function MyExceptionHandler(Exception) 
    if (Exception instanceof TypeError || 
        Exception instanceof ReferenceError || 
        Exception instanceof RangeError ||  
        Exception instanceof SyntaxError ||     
        Exception instanceof URIError ) 
        throw Exception; // native error
      else 
         // handle exception
     

MyExcetpionHandler 将抛出原生错误,因为没有 try-catch 块。

访问http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/

【讨论】:

【参考方案5】:

try-catch 并不总是最好的解决方案。例如,在 Chrome 7.0 中,您会在控制台窗口中丢失漂亮的堆栈跟踪。重新抛出异常没有帮助。我不知道有任何解决方案可以保留堆栈跟踪让您对异常做出反应。

【讨论】:

【参考方案6】:

通过一些工作,可以获得在所有浏览器中相当完整的堆栈跟踪。

现代 Chrome 和 Opera(即基于 Blink 渲染引擎的任何东西)完全支持 ErrorEvent 和 window.onerrorhtml 5 草案规范。在这两种浏览器中,您都可以使用window.onerror,或者(非常棒!)正确绑定到“错误”事件:

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) 
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
;
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) 
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendData(data);
)

不幸的是,Firefox、Safari 和 IE 仍然存在,我们也必须支持它们。由于堆栈跟踪在 window.onerror 中不可用,我们必须做更多的工作。

事实证明,要从错误中获取堆栈跟踪,我们唯一能做的就是将所有代码包装在 try catch(e) 块中,然后查看 e.stack。我们可以使用一个名为 wrap 的函数来简化这个过程,该函数接受一个函数并返回一个具有良好错误处理能力的新函数。

function wrap(func) 
    // Ensure we only wrap the function once.
    if (!func._wrapped) 
        func._wrapped = function () 
            try
                func.apply(this, arguments);
             catch(e) 
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendData(data);
                throw e;
            
        
    
    return func._wrapped;
;

这行得通。您手动包装的任何函数都将具有良好的错误处理能力。

您可以使用图像标签发送数据,如下所示

function sendData(data) 
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() 
        console.log('success', data);
    ;
    img.onerror = img.onabort = function failure() 
        console.error('failure', data);
    ;
    img.src = src;

但是,您必须做后端来收集数据和前端来可视化数据。

Atatus,我们正在努力解决这个问题。 Atatus 不仅提供错误跟踪,还提供真实的用户监控。

试试https://www.atatus.com/

免责声明:我是 Atatus 的一名网络开发人员。

【讨论】:

【参考方案7】:

确实,在现代浏览器中,将 window.onerror 挂接到一直冒泡到顶部的错误,并为 Ajax 错误添加 jQuery 事件处理程序,几乎可以捕获客户端代码中抛出的所有 Error 对象。如果您手动设置 window.onerror 的处理程序,在现代浏览器中,这是通过 window.addEventListener('error', callback) 完成的, 而在 IE8/9 中你需要调用 window.attachEvent('onerror', callback).

请注意,您应该考虑处理这些错误的环境以及这样做的原因。使用堆栈跟踪捕获尽可能多的错误是一回事,但是现代 F12 开发工具的出现解决了在本地实施和调试时的这个用例。断点等将为您提供比处理程序可用的更多数据,特别是对于从 CORS 请求加载的第三方库引发的错误。您需要采取额外的步骤来指示浏览器提供这些数据。

关键问题是在生产环境中提供这些数据,因为保证您的用户运行的浏览器和版本范围远远超出您可能测试的范围,并且您的网站/应用会以意想不到的方式中断,无论质量保证多少你扔它。

要处理此问题,您需要一个生产错误跟踪器,该跟踪器会在用户使用您的代码时获取用户浏览器中抛出的每个错误,并将它们发送到您可以查看数据并用于修复错误的端点当它们发生时。在 Raygun(免责声明:我在 Raygun 工作),我们付出了很多努力来为此提供出色的体验,因为有许多陷阱和问题需要考虑,因为幼稚的实现会错过。

例如,您可能会捆绑和缩小您的 JS 资产,这意味着从缩小的代码中抛出的错误将包含带有错误变量名的垃圾堆栈跟踪。为此,您需要您的构建工具来生成源映射(我们推荐使用 UglifyJS2 作为管道的这一部分),以及您的错误跟踪器来接受和处理这些,将损坏的堆栈跟踪转换回人类可读的堆栈跟踪。 Raygun 开箱即用,并包含一个 API 端点来接受源映射,因为它们是由您的构建过程生成的。这是关键,因为它们需要保持非公开,否则任何人都可以取消您的代码,从而否定其目的。

raygun4js 客户端库还附带 window.onerror,适用于现代和旧版浏览器,以及开箱即用的 jQuery 挂钩,因此您只需添加:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

还有一系列内置功能,包括在发送错误有效负载之前对其进行变异、添加标签和自定义数据、看到错误的用户的元数据。它还消除了从上述第三方 CORS 脚本中获取良好堆栈跟踪的痛苦,这解决了可怕的“脚本错误”(不包含错误消息,也没有堆栈跟踪)。

一个更关键的问题是,由于网络上的大量受众,您的网站会为每个错误生成数千个重复实例。像 Raygun 这样的错误跟踪服务可以将这些错误汇总到错误组中,这样您就不会淹没在大量通知中,并且可以让您看到每个实际错误都准备好修复。

【讨论】:

【参考方案8】:

我也在寻找错误处理和堆栈跟踪以及用户操作日志记录这就是我发现的希望这也可以帮助你 https://github.com/jefferyto/glitchjs

【讨论】:

【参考方案9】:

最好的错误处理程序:

try 
    // something
 catch(e) 
    window.location.href = "https://***.com/search?q=[js] + " + e.message

【讨论】:

以上是关于JavaScript 异常处理的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript的异常处理

javascript 异常处理使用总结

JavaScript 异常处理 - 显示行号

javaScript基础异常处理

JavaScript 异常处理

JavaScript异常处理