如何完全准备好异步递归方法时创建回调

问题描述 投票:0回答:2

我需要一个递归函数,以与在递归完全完成之后发生的回调异步发生。我简化了它以除去不相关的部分(这里是jsfiddle中的代码。

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应该能够执行多次,而不必等待先前的调用完成。

javascript asynchronous recursion callback
2个回答
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]));
            }
        }
    }
};

0
投票

[不添加额外的超时时间,一种方法是在不实际执行任何主要任务的情况下进行树的第一次遍历,而是计算复活次数。假设您的树不大,您应该能够同步执行此操作而无需锁定浏览器。

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

© www.soinside.com 2019 - 2024. All rights reserved.