异步异常
最近用request call 一个webservice 做个测试。代码如下,request 函数被 try-catch 包括着,这样当失败时打印一些log。这里没有使用 Promise。
- var request = require('request');
- var url = "http://xxxx.xxx.com/ssss/sss";
- try {
- request(url, function(error, response, body) {
- if (!error && response.statusCode == 200) {
- console.log(body)
- } else {
- throw new Error("Call WebService Error")
- }
- })
- } catch (e) {
- // 这里并不能捕获回调里面抛出的异常
- console.log("-----catch error------")
- console.log(e)
- }
- try {
- // 同步代码
- } catch (e) {
- // 捕获同步异常
- }
之后查看一些文档发现 无论是Node中 还是浏览器环境中,都提供了对捕获这类异常的支持。下面来看一下:
Node
在我们的代码中添加下面一段代码。- process.on('uncaughtException', function (err) {
- // todo
- });
- var request = require('request');
- process.on('uncaughtException', function (err) {
- console.log('---------catch--exception--------------');
- console.log(err);
- // process.exit(1);// 退出
- // server.close(function(){
- // // todo
- // })
- });
- var url = "http://xxxx.xxx.com/ssss/sss";
- try {
- request(url, function(error, response, body) {
- if (!error && response.statusCode == 200) {
- console.log(body)
- } else {
- throw new Error("Call WebService Error")
- }
- })
- } catch (e) {
- // 这里并不能捕获回调里面抛出的异常
- console.log("-----catch error------")
- console.log(e)
- }
浏览器
在浏览器中,很多时候出现Error,整个页面就挂掉了。相反,如果我们能catch 这些Error,然后弹出一些友好界面会有更好的体验。在window对象下有个 onerror 属性。- // 在浏览器中
- window.onerror = function(msg, file, line, col, error) {
- // todo process error
- };
- <!DOCTYPE html>
- <html>
- <head>
- </head>
- <body>
- <button onclick="afterclick()">Button</button>
- <script type="text/javascript">
- function afterclick() {
- throw new Error("My throw Error", "Throw error function");
- }
- window.onerror = function(msg, file, line, col, error) {
- alert("Something error happen, please try again later!")
- };
- </script>
- </body>
- </html>
domain
从上面两点可以发现,如果可以通过某种方式来捕获回调函数中的异常,那么就不会有 uncaughtException 错误导致的崩溃。对此,Node 提供了一个很有用的模块- domain模块,它可以用来捕获回调函数中抛出的异常。官方文档
domain 主要有两个api 函数,run 和 error 事件。即 run里面执行出现的异常都能被 error 时间捕获。例如:
- var request = require('request');
- var domain = require('domain');
- var d = domain.create();
- var url = "http://xxxx.xxx.com/ssss/sss";
- d.run(function () {
- request(url, function(error, response, body) {
- if (!error && response.statusCode == 200) {
- console.log(body)
- } else {
- throw new Error("Call WebService Error")
- }
- })
- });
- d.on('error', function (err) {
- console.log('Already catch err: ', err);
- });
到了这里,你可能觉得很完美了。可惜的是,domain 也有个问题,它并不能捕获所有的异步异常。这里有个社区的帖子,讲解的很很详细。
http://cnodejs.org/topic/516b64596d38277306407936
因此,好的做法是 domain + uncaughtException。