JavaScript异常处理


82

捕获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时的建议准则。


只是因为很明显您没有注意到我的回答:当您将它读为“似乎是对问题的陈述”时,您似乎对我不满意:“但是Opera和Safari呢?” 我专门回答了这里提出的一个问题。WTF?
2008年

1
window.onerror2003年以来,在WebKit中,丢失一直是一个问题,但看来终于可以解决了。当然,歌剧将保持固执。
josh3736

仅供参考window.onerror在-Firefox 7.0.1-IE 8-Chrome 16-Opera 11.60
Vitaliy Kaplich 2012年

11
不知道为什么关闭它。投票重新开放。
ripper234 '02

1
同意,这是一个有用的问题。我唯一能想到的就是casperOne担心这会成为某种浏览器之战的话题吗?
Jordan Reiter 2012年

Answers:


23

如果使用类似jQuery的库来分配所有事件处理程序,则可以window.onerror将jQuery事件处理程序代码和on ready函数与错误处理函数结合使用和包装(请参阅:JavaScript错误跟踪:为什么window.onerror不够用))。

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

我已经读过没有提供任何解决方案的文章。我不使用jQuery,但我担心您的意思。您是说jQuery正在吃异常吗?还是它们仅提供日志记录功能(仅在回答我的原始问题后才有用)?
harley.333,

jQuery对异常没有任何特殊的处理。但是,如果您使用jQuery来添加所有事件,则可以在一个地方添加try catch语句和错误处理代码,如答案中第二个链接所述。
卡尔

2
提供的链接移动:blogs.cozi.com/tech/2008/04/...
natacado

1
这仍然是真的吗?我刚刚onerror在Safari + Chrome上尝试了正常的处理方法,但似乎工作正常。
朱里2012年

您提供的指向“为什么还不够”的链接是很旧的信息,而现在并非如此。
vsync 2014年

21

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

原始帖子:据我所知,WebKit / Safari不支持该onerror事件。真可惜。


19
呃,不,不是。在问题中被问到:“但是Opera和Safari呢?”
2008年

在这种情况下,我专门回答了问题帖中提出的问题。
2008年

8
我认为他的意思是“关于Opera和Safari [没有window.onerror]的[我该怎么办?”?
尼克

10
@nickf,也许,但是如果这样的话,它的措词很不好,而且我的解释最糟糕的是可以理解的,充其量是最有可能的。人们否定我的答案是一个很糟糕的理由,特别是考虑到该问题并未 说明问题,其他读者可能会从肯定或否定的陈述中受益。
失眼

Chrome现在似乎支持它。
Daniel X Moore

7

实际上,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 });
});

11
对于现在发现此问题的任何人-jQuery实际上建议不要将事件绑定到window.error事件-请参阅上面的文档链接。提取:不应将jQuery错误事件处理程序附加到window对象。[...]改用window.onerror。
zcrar70 2011年

ofc不应以这种方式绑定,这是不合逻辑的!进行此次出价时可能会发生许多错误(如果成功进行了……)
vsync

6

使用您自己的异常处理程序捕获所有异常并使用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
     }
}

由于没有try-catch块,因此MyExcetpionHandler将引发本机错误。

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


4

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


2

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

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

// 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仍然存在,我们也必须支持它们。由于stacktrace不可用,因此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的一名Web开发人员。


1

的确,对于现代浏览器,将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之类的错误跟踪服务可以将这些错误汇总到错误组中,因此您不会陷入大量通知中,并且可以查看每个实际已准备好修复的错误。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.