在NodeJS中编写域名感知函数 [英] Writing Domain Aware Functions in NodeJS

查看:99
本文介绍了在NodeJS中编写域名感知函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图想出一个在NodeJS中处理异常的一般(有意的)方式,由于性能的影响,它不会使用try catch。我也想远离图书馆,像流线型,试图使异步代码看起来像同步代码。



似乎域名符合账单,但我想邀请评论/我建议使用它们的建议。这个方法有很大的问题吗?



我打算使大多数异步函数遵循以下domainAware函数的模式:

  function errorinAsync(options,callback){
options = options || {};
setTimeout(function(){
return callback(new Error(This should be catch));
},1000);

}
函数domainAware(options,callback){
if(domain.active){
d = domain.active;
} else {
d = domain.create();
d.on('error',function(err){
return callback(err);
});
}

d.run(function(){
//可能引发异常的某些同步代码;
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!',呃);
});
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);
});
}

函数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(){
//某些可能引发异常的同步代码;
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);

}

函数callThroughDomain(fn,callback){
var d = domain.create();
d.on('error',function(er){
console.error('Caught error!',呃);
});
d.run(function(){
fn(1000000,d.intercept(callback));
});
}

我开始使用控件:

  function tryCatchCallback(j,callback){
try {
var s = 0; (var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;

doSomethingAsync(null,function(err){
//就像domain.intercept一样,回调中的异常被处理
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; $ b $ (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);
}
}

函数外(j,回调){
var s = 0; (var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;

doSomethingAsync(null,function(err){
//再次从回调中捕获错误
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场景的显着性能增益。 >

最后比较尝试使用外部函数体的域

 函数domainWithOuter(j,callback){
var d = domain.active || domain.create()。on('error',function(err){return callback(err);});

d.run(function(){
outerNoHandler(j,callback);
});
}

函数outerNoHandler(j,callback){
var s = 0; (var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;
(var i = 0; i< j; i ++)s = i;

doSomethingAsync(null,function(err){
//不需要try catch
//由域管理的异常
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在封面下,他们需要使用以类似的方式与相同的性能警告。


I am trying to come up with a general (opinionated) way of handling exceptions in NodeJS that doesn't use try catch due to the performance hit. I also want to stay away from libraries like streamline that try to make async code look like sync code.

It seems that Domains fit the bill well but I wanted to invite comments/ suggestions on the way I propose to use them. Are there significant problems with this approach?

I plan to make the majority of my async functions follow the pattern of the domainAware function below:

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);
        }));
    });
}

What I want to do is avoid throwing an error in an async function. This is mainly for situations where I don't have any specific exceptions that I want to handle but I want to ensure that exceptions don't get 'lost'.

I can call it with a domain context:

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");
    }));
});

Or without one:

domainAware(null, function(err){
    if(err){
        return console.log("Caught Error from Callback" + err);
    }
    console.log("all Done");
});

This contrived example works well, but what about more complex scenarios with many functions.

Update: #1

An equivalent function using try catch might be:

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);
    }
}

I will do some performance tests on these two approaches to see if there is any difference.

Other than performance is there any other problem with using the domain based approach? A revised version of the domain aware function could look like this.

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);
        }));
    });
}

I like the simplicity of the domain based version, but is it more or less equivalent? Of course you do need to remember to use d.intercept or check the err of any callbacks, but I can handle that.

解决方案

UPDATE

I have done some more work on this and found a great way of writing async functions using domains that eliminates most of the exception handling boilerplate and performs better than try catch exception handling in some cases:

http://www.lighthouselogic.com/using-a-new-domain-for-each-async-function-in-node/

This supersedes much of what is written in the post below. In fact the function useExistingDomainifAvailable that I proposed below has side effects that I didn't consider when writing this original answer. The main one being that error handling is always done via a short circuit back to the domain exception handler rather than through the callback chain.

UPDATE

So, I did some performance testing and found that the domain version is actually about the same as wrapping the function body in a try catch:

The following two functions were used in all my tests:

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));
    });
}

I started with a control:

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);
        }
}

The test for which was:

callThroughDomain(tryCatchCallback, function(){
    deferred.resolve();
});

Then I tried with using the pre-declared domain:

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();
});

Then I tried with the guts of the function being called by an external 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();
});

The results of my benchmark.js tests are as follows:

control x 42.12 ops/sec ±0.83% (38 runs sampled)
useExistingDomainifAvailable x 41.98 ops/sec ±6.67% (44 runs sampled)
tryCatchOuter x 93.23 ops/sec ±2.07% (66 runs sampled)
Fastest is tryCatchOuter

Showing a significant performance gain for the tryCatchOuter scenario.

And for a final comparison trying the domains with the external function body

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);
    });
}

control x 42.75 ops/sec ±1.06% (39 runs sampled)
useExistingDomainifAvailable x 42.86 ops/sec ±6.81% (38 runs sampled)
tryCatchOuter x 95.86 ops/sec ±2.35% (68 runs sampled)
domainWithOuter x 94.65 ops/sec ±1.91% (67 runs sampled)
Fastest is tryCatchOuter,domainWithOuter

So essentially using the domain is the same as using try catch in terms of performance in this case with some differences in syntax.

I guess because domain.run and doman.intercept use try catch under the covers, they need to be used in a similar way with the same performance caveats.

这篇关于在NodeJS中编写域名感知函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆