在nodejs中,是否存在更好的设计模式来同步调用异步函数? [英] In nodejs, is there a better design pattern to call async functions synchronously?

查看:162
本文介绍了在nodejs中,是否存在更好的设计模式来同步调用异步函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我想编写一个测试用例,需要跟踪一系列调用的状态。

For example, I want to write a test case, which need to track the status of a series calls.

我可以得到这样的东西:

I can get something like this:

async_fun(function () {
    // Do something ...

    async_fun(function () {
        // Do something ...

        async_fun(function () {
            // Do something ...
            // ...
        });
    });
});

async_fun();

当我需要运行一个大循环时,可以创建一个尾递归,如下所示:

When I need to run a large loop, I can make a tail recursion like below:

function helper (mount) {
    async_fun(function (){
        if (mount) return;

        // Do something ...

        helper(mount--);
    });
}

helper(10000);

但是,我听说V8引擎没有对尾调用,因此它可能会耗尽RAM。有更好的设计模式可以完成此任务吗?

But, I heard that V8 engine has no optimization for the tail call, so it may eat up the RAM. Is there a better design pattern to achieve this task?

PS:请没有第三个库。我想要一个本机解决方案。

PS: No third lib please. I want a native solution.

推荐答案

对于第二个示例,我建议使用事件。如果使用注册的事件以及全局(或闭包)计数器,它将阻止调用堆栈的增长,但实现相同的逻辑。假设countDown方法执行一些异步工作,只需将该异步工作传递给回调,该回调将在行中发出下一个事件。

For your second example I recommend using events. If you use registered events, along with a global(or closure) counter, it will keep the call stack from growing, but achieve the same logic. Assume the countDown method does some asynchronous work, just pass this async work a callback that emits the next event in line.

var events = require("events");

function recursiveCountDown(someVariable) {
    var counter = someVariable;
    var eventEmitter = new events.EventEmitter();//create a new event object, so we can have lots of these running potentially without interfering with one another!
    var eventName = 'count';

    function countDown()  {
        someVariable--;
        console.log(someVariable);
        if(someVariable) eventEmitter.emit(eventName);
    }

    eventEmitter.on(eventName, countDown);

    eventEmitter.emit(eventName);
}

recursiveCountDown(1000);

对于第一个问题,有几个可用的流控制库。老实说,您已经以一种较为讨厌的方式组织了此活动。您可以做一些组织上的事情来使这个更好,但是最终它们看起来都只会好一点。无法避免这种逻辑流程,从我的角度来看,我更喜欢看到如何执行事情。但是,这只是一个意见。您可以查看一些流控制库,ASYNC似乎是标准。基本上,它允许您将函数呈现为好像是按行执行,尽管实际上它们在内部被包装和执行为与上面介绍的完全相同的连续回调。我更喜欢以下成语:

For your first issue there are several flow control libraries available. To be honest, you have organized this in one of the more nasty ways. There are some organizational things you can do to make this "better", but they all end up looking only marginally better. There is no way to avoid this flow of logic, and from my point of view, I prefer seeing how things get executed. But, this is just an opinion. You can look into some of the flow control libraries, ASYNC seems to be the standard. Basically, what it allows, is for you to present your functions as if they were executing in line, despite the fact that internally they are being wrapped and executed as successive callbacks exactly like you have presented above. I prefer the following idiom:

function doABunchOfAsyncWorkInSeries(arg, callbackToMainEventLoop) {
    var sharedByAll = 'OUTPUT: '
    setTimeout(function(){
        console.log(sharedByAll + arg);
        asyncFun2('a different string');
    }, 1000);

    function asyncFun2(arg2) {
        setTimeout(function() {
            console.log(sharedByAll + arg2);
            asyncFun3('final string');
        }, 2000);
    }

    function asyncFun3(arg3) {
        setTimeout(function(){
            console.log(sharedByAll +arg3);
            callbackToMainEventLoop('FINISHED');
        }, 3000);
    }
}

doABunchOfAsyncWorkInSeries('first string', function(arg) {
    console.log('The program is finished now. :' + arg);
});

请注意,逻辑流程本质上是相同的,但是功能是串联编写的。因此很明显,尽管doSomeWork ....函数可以异步执行而不影响逻辑流程,但一个命令接一个执行。在您的示例中,您执行相同的操作,但是每个连续的函数在其闭包中都包含另一个函数……没有理由这样做。这看起来更干净一点。同样,如果您不介意库为您做这样的事情,为简化语法,请查看Async。但是在内部,这就是异步正在做的事情。老实说,我更喜欢这种语法。

Notice that the flow of logic is essentialy the same, but the functions are written in series. So it is clear that one is executing after the other, despite the fact that the doSomeWork.... functions can be asyncrhonous without effecting logic flow. In your example you do the same thing, but each consecutive function contains another function within its closure... There's no reason to do it this way. This just looks a little cleaner. Again, if you don't mind libraries doing things like this for you, to simplify your syntax, look into Async. But internally, this is what Async is doing. And I honestly like this syntax better.

这篇关于在nodejs中,是否存在更好的设计模式来同步调用异步函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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