如何在异步递归方法完全就绪时创建回调?

时间:2011-12-19 15:45:31

标签: javascript asynchronous recursion callback

我需要一个异步发生的递归函数,回调完全结束后会发生回调。我简化它以摆脱不相关的部分(这里是jsfiddle中的代码:http://jsfiddle.net/DgaBg/8/

tree = {
    "a": {
        "b": 1,
        "c": 2
    },
    "d": {
        "e": {
            "f": {
                "g": 3
            },
            "h": 4,
            "i": 5
        },
        "j": {
            "k": 6,
            "l": 7
        },
        "m": 8,
        "n": 9
    },
    "o": {
        "p": 10
    },
    "q": 11
};

Watcher = function() { };

Watcher.prototype.startDoingAsyncStuff = function(node, callback) {
    var me = this,
        key;

    if(typeof node === "number") {
        console.log(node);
    } else {
        for(key in node) {
            if(node.hasOwnProperty(key)) {
                (function(node) {
                    setTimeout(function() {
                        me.startDoingAsyncStuff(node, callback);
                    }, 500);
                }(node[key]));
            }
        }
    }
};

w = new Watcher();

w.startDoingAsyncStuff(tree, function() {
    console.log("callback 1");
});

w.startDoingAsyncStuff(tree["d"], function() {
    console.log("callback 2");
});

我需要在重复完成后提供给Watcher.startDoingAsyncStuff的回调才能执行,但我不知道如何实现这一点。

这里的复杂因素是无法使用简单的计数器,因为Watcher.startDoingAsyncStuff应该能够执行多次,而无需等待之前的调用完成。

对此的任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

基本上,对于子东西,你想要提供一个回调,它只是通知它上面的级别已完成。在更高级别,您有一些预期会收到的“已完成”消息,一旦获得该号码,您就会调用“真实”回调。

我最初有一个计数器原型,它在功能之外执行此操作,但实际功能非常简单,我将其合并到功能本身。

Watcher.prototype.startDoingAsyncStuff = function(node, callback) {
    var me = this,
        key,
        jobCount = 0;

    if (typeof node === "number") {
        console.log(node);
        // There's no sub-stuff to do, so we're done here
        callback();
    } else {
        for (key in node) {
            if (node.hasOwnProperty(key)) {
                (function(node) {
                    ++jobCount;
                    setTimeout(function() {
                        // we create a sub-callback to decrement the counter
                        // and run the "real" callback when the counter is back
                        // to 0.
                        // This works as many times as needed, because jobCount
                        // is local and accessed via closure.
                        me.startDoingAsyncStuff(node, function() {
                            if (--jobCount == 0) callback();
                        });
                    }, 500);
                }(node[key]));
            }
        }
    }
};

答案 1 :(得分:0)

如果不添加额外的超时,一种方法是在不实际执行任何主要任务的情况下进行树的第一次传递,而是计算重新生成的次数。假设您的树不是很大,您应该能够在不锁定浏览器的情况下同步执行此操作。

然后做第二遍,并在执行每个主要异步任务后增加另一个计数器;当它与第一遍的计数匹配时,你可以触发回调。