我正在尝试提出一种处理NodeJS中异常的通用(有针对性的)方法,由于性能下降,该方法不使用try catch。我也想远离简化的库,这些库试图使异步代码看起来像同步代码。
域名似乎很适合该法案,但我想邀请我就其使用方式提出意见/建议。这种方法是否存在重大问题?
我计划使大多数异步函数遵循以下domainAware函数的模式:
function errorinAsync(options, callback){
options = options || {};
setTimeout(function(){
return callback(new Error("This should be caught"));
},1000);
}
function domainAware(options, callback){
if(domain.active){
d = domain.active;
}else{
d = domain.create();
d.on('error', function(err){
return callback(err);
});
}
d.run(function(){
//Some Synchronous code that might throw an exception;
var a = {b: 1, c: 2};
var thing = JSON.stringify(a);
errorinAsync(null,d.intercept(function(err) {
return callback(null);
}));
});
}
我想做的是避免在异步函数中引发错误。这主要用于以下情况:我没有要处理的任何特定异常,但是我想确保异常不会丢失。
我可以用域上下文来称呼它:
var d = domain.create();
d.on('error', function(er) {
console.error('Caught error!', er);
});
d.run(function() {
domainAware(null, d.intercept(function(err) {
console.log("all Done");
}));
});
还是没有一个:
domainAware(null, function(err){
if(err){
return console.log("Caught Error from Callback" + err);
}
console.log("all Done");
});
这个人为的示例效果很好,但是具有许多功能的更复杂的方案呢?
更新:#1
使用try catch的等效功能可能是:
function noHandling(callback){
var a = {b: 1, c: 2};
var thing = JSON.stringify(a);
errorinAsync(null,function(err) {
if(err) return callback(err);
return callback(null);
});
}
function notDomainAware(options, callback){
try{
noHandling(callback);
}catch(err){
callback(err);
}
}
我将对这两种方法进行一些性能测试,以查看是否存在任何差异。
除了性能以外,使用基于域的方法还有其他问题吗?域识别功能的修订版可能如下所示。
function domainAware(options, callback){
var d = domain.active || domain.create().on('error', function(err){ return callback(err); });
d.run(function(){
//Some Synchronous code that might throw an exception;
var a = {b: 1, c: 2};
var thing = JSON.stringify(a);
errorinAsync(null,d.intercept(function(err) {
return callback(null);
}));
});
}
我喜欢基于域的版本的简单性,但它或多或少是等效的?当然,您确实需要记住使用d.intercept或检查任何回调的错误,但是我可以处理。
最佳答案
更新
我对此进行了更多工作,找到了一种使用域编写异步函数的好方法,该方法消除了大多数异常处理样板,并且在某些情况下比尝试捕获异常处理要好:
http://www.lighthouselogic.com/using-a-new-domain-for-each-async-function-in-node/
这将取代以下文章中的大部分内容。实际上,我在下面提出的函数useExistingDomainifAvailable具有副作用,在编写此原始答案时我没有考虑过。主要的问题是错误处理总是通过短路返回域异常处理程序来完成,而不是通过回调链来完成。
更新
因此,我进行了一些性能测试,发现域版本实际上与将函数体包装在try catch中相同:
我的所有测试中都使用了以下两个功能:
function doSomethingAsync(options, callback){
options = options || {};
setTimeout(function(){
return callback(null);
},1);
}
function callThroughDomain(fn, callback) {
var d = domain.create();
d.on('error', function(er) {
console.error('Caught error!', er);
});
d.run(function() {
fn(1000000, d.intercept(callback));
});
}
我从一个控件开始:
function tryCatchCallback(j, callback) {
try{
var s = 0;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
doSomethingAsync(null, function(err){
//Just like domain.intercept, exceptions in the callback are handled
try{
if(err) return callback(err);
callback(s);
}catch(ex){
callback(ex);
}
});
}
catch(ex) {
callback(ex);
}
}
的测试是:
callThroughDomain(tryCatchCallback, function(){
deferred.resolve();
});
然后,我尝试使用预声明的域:
function useExistingDomainifAvailable(j, callback) {
var d = domain.active || domain.create().on('error', function(err){ return callback(err); });
d.run(function(){
var s = 0;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
doSomethingAsync(null, d.intercept(function(err){
callback(s);
}));
});
}
callThroughDomain(useExistingDomainifAvailable, function(){
deferred.resolve();
});
然后我尝试了由外部try catch调用的函数的胆量
function tryCatchOuter(j, callback) {
try{
outer(1000000, callback);
}catch(e){
console.log(e);
}
}
function outer(j, callback) {
var s = 0;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
doSomethingAsync(null, function(err){
//Again catching errors from callback
try{
if(err) return callback(err);
callback(s);
}catch(ex){
callback(ex)
}
});
}
callThroughDomain(tryCatchOuter, function(){
deferred.resolve();
});
我的Benchmark.js测试的结果如下:
控制x 42.12 ops / sec±0.83%(采样了38个运行)
useExistingDomainifAvailable x 41.98 ops / sec±6.67%(已采样44个运行)
tryCatchOuter x 93.23 ops / sec±2.07%(66次运行采样)
最快的是tryCatchOuter
在tryCatchOuter方案中显示出显着的性能提升。
最后尝试将域与外部函数主体进行比较
function domainWithOuter(j, callback) {
var d = domain.active || domain.create().on('error', function(err){ return callback(err); });
d.run(function(){
outerNoHandler(j,callback);
});
}
function outerNoHandler(j, callback) {
var s = 0;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
for (var i = 0; i < j; i++) s = i;
doSomethingAsync(null, function(err){
//Don't need try catch here
//Exceptions managed by domain
if(err) return callback(err);
callback(s);
});
}
对照x 42.75 ops / sec±1.06%(采样了39个运行)
useExistingDomainifAvailable x 42.86 ops / sec±6.81%(采样了38个运行)
tryCatchOuter x 95.86 ops / sec±2.35%(采样了68个运行)
domainWithOuter x 94.65 ops / sec±1.91%(采样了67个运行)
最快的是tryCatchOuter,domainWithOuter
因此,在这种情况下,本质上使用域与使用try catch相同,但语法有所不同。
我猜是因为domain.run和doman.intercept在幕后使用try catch,所以它们需要以类似的方式使用,但要注意相同的性能。
关于javascript - 在NodeJS中编写域感知功能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17498222/