简体   繁体   English

在nodejs中,是否存在更好的设计模式来同步调用异步函数?

[英]In nodejs, is there a better design pattern to call async functions synchronously?

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

But, I heard that V8 engine has no optimization for the tail call , so it may eat up the RAM. 但是,我听说V8引擎没有对tail调用进行优化,因此可能会耗尽RAM。 Is there a better design pattern to achieve this task? 是否有更好的设计模式来完成此任务?

PS: No third lib please. 附言:请不要三句。 I want a native solution. 我想要一个本机解决方案。

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. 假设countDown方法执行一些异步工作,只需将此异步工作传递给回调即可发出下一个事件。

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

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. 您可以查看一些流控制库,ASYNC似乎是标准。 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);
});

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. 因此很明显,尽管doSomeWork ....函数可以异步执行而又不影响逻辑流,但事实是一个接一个地执行。 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. 同样,如果您不介意库为您做这样的事情,为简化语法,请查看Async。 But internally, this is what Async is doing. 但是在内部,这就是异步正在做的事情。 And I honestly like this syntax better. 老实说,我更喜欢这种语法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM