Javascript 在NodeJS中编写域感知函数
我正试图想出一种处理NodeJS中异常的通用(固执己见的)方法,由于性能受到影响而不使用try-catch。我还想远离像streamline这样试图使异步代码看起来像同步代码的库 看起来域名很适合这个法案,但我想邀请大家对我提议的使用方式提出意见/建议。这种方法是否存在重大问题 我计划使我的大多数异步函数遵循以下domainAware函数的模式:Javascript 在NodeJS中编写域感知函数,javascript,node.js,exception-handling,Javascript,Node.js,Exception Handling,我正试图想出一种处理NodeJS中异常的通用(固执己见的)方法,由于性能受到影响而不使用try-catch。我还想远离像streamline这样试图使异步代码看起来像同步代码的库 看起来域名很适合这个法案,但我想邀请大家对我提议的使用方式提出意见/建议。这种方法是否存在重大问题 我计划使我的大多数异步函数遵循以下domainAware函数的模式: function errorinAsync(options, callback){ options = options || {};
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或检查任何回调的错误,但我可以处理它。UPDATE
我在这方面做了更多的工作,发现了一种使用域编写异步函数的好方法,它消除了大多数异常处理样板文件,在某些情况下比try-catch异常处理性能更好:
这取代了下文中的大部分内容。事实上,下面我所提出的可用函数的存在有副作用,我在写这个原始答案时没有考虑。最主要的一点是,错误处理总是通过与域异常处理程序的短路来完成,而不是通过回调链
更新
因此,我做了一些性能测试,发现域版本实际上与在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);
}
}
然后我尝试使用预先声明的域:
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();
});
函数UseExistingDomainiAvailable(j,回调){
var d=domain.active | | domain.create().on('error',function(err){return callback(err);});
d、 运行(函数(){
var s=0;
对于(var i=0;i
然后我尝试使用外部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();
});
函数tryCatchOuter(j,回调){
试一试{
外部(1000000,回拨);
}捕获(e){
控制台日志(e);
}
}
函数外部(j,回调){
var s=0;
对于(var i=0;i
我的benchmark.js测试结果如下:
控制x 42.12次/秒±0.83%(取样38次)使用现有域可用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);
});
}
函数域WithOuter(j,回调){
var d=domain.active | | domain.create().on('error',function(err){return callback(err);});
d、 运行(函数(){
外把手(j,回叫);
});
}
函数outerNoHandler(j,回调){
var s=0;
对于(var i=0;i
控制x 42.75次/秒±1.06%(取样39次)使用现有域可用x 42.86 ops/sec±6.81%(采样38次)
tryCatchOuter x 95.86 ops/sec±2.35%(采样68次)
域外x 94.65次/秒±1.91%(取样67次)
最快的是tryCatchOuter,domainWithOuter 因此,在本例中,就性能而言,使用域与使用try-catch基本相同,但在语法上有所不同
我想,因为domain.run和doman.intercept在幕后使用try-catch,所以它们需要以类似的方式使用,并具有相同的性能警告。try-catch只会减慢它周围的代码,因此try{doSomethingSlow()}不会因为优化障碍而减慢被调用函数的速度。@dandavis,我已经做了一个更新,包含了与try-catch等效的版本。我将做一些性能测试,看看是否有任何差异
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);
});
}