1

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

我可以得到这样的东西:

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

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

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

async_fun();

当我需要运行一个大循环时,我可以进行如下的尾递归

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

        // Do something ...

        helper(mount--);
    });
}

helper(10000);

但是,我听说 V8 引擎没有对尾调用进行优化,所以它可能会吃掉 RAM。是否有更好的设计模式来完成这项任务?

PS:请不要第三个库。我想要一个本地解决方案。

4

1 回答 1

2

对于您的第二个示例,我建议使用事件。如果您使用注册事件以及全局(或闭包)计数器,它将阻止调用堆栈增长,但实现相同的逻辑。假设 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);

对于您的第一个问题,有几个可用的流控制库。老实说,您以一种更讨厌的方式组织了这个。你可以做一些组织上的事情来让它“更好”,但它们最终看起来都只是稍微好一点。没有办法避免这种逻辑流,从我的角度来看,我更喜欢看看事情是如何执行的。但是,这只是一个意见。您可以查看一些流控制库,ASYNC 似乎是标准。基本上,它允许您呈现您的函数,就好像它们是在行中执行一样,尽管事实上它们在内部被包装并作为连续回调执行,就像您在上面介绍的那样。我更喜欢以下成语:

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。但在内部,这就是 Async 正在做的事情。老实说,我更喜欢这种语法。

于 2013-07-29T14:42:30.223 回答