3

我在搜索函数中有一个 for 循环,其中一个执行回调的函数在循环内执行回调,并且我想在循环之后执行 BUILD() 函数,并且在所有回调完成之后。我不知道该怎么做,因为循环在所有回调完成之前完成。回调是获取我数据的 API 请求,我想用该数据构建()。

我阅读了deferred,所以我尝试将for循环放在deferred的函数中,然后在'.then(...)'上调用BUILD()。但这似乎不起作用-我想我理解错了。

帮助?!

请注意,这是使用 Google Maps Places API(搜索和 getDetails)。

var types = {
    'gym' : 'fitness, gym',
    'grocery_or_supermarket': ''
}

function search() {
    for (var key in types) {
         var request = { ... };
         service.search(request, searchCallback);
    }
    // PROBLEM AREA
    BUILD();
}

function searchCallback(results, status) {
    for (var i = 0; i < results.length; i++) {
        var request = { ... };
        service.getDetails(request, detailsCallback);
    }
}

function detailsCallback(place, status) {
    // add place marker to maps and assign info window and info window event
}
4

2 回答 2

3

只需对您的代码稍作修改,就可以实现。

var total = 1337; // Some number
var internal_counter = 0;
var fn_callback = function() {
    searchCallback.apply(this, arguments);
    if (++internal_counter === total) {
        BUILD();
    }
};
for (var i=0; i<total; i++) {
    service.search(request, fn_callback);
    ...

解释

首先,我们创建一个局部函数和变量。

  • 该变量是一个计数器,在调用回调时会增加。
  • 该函数被传递给service.search调用原始回调的异步方法 ()。增加计数器后,根据包含迭代总数的变量检查计数器的值。如果它们相等,则调用整理函数 ( BUILD)。

一个复杂的案例:处理嵌套回调。

var types = { '...' : ' ... ' };

function search() {
    var keys = Object.keys(types);
    var total = keys.length;
    // This counter keeps track of the number of completely finished callbacks
    //  (search_callback has run AND all of its details_callbacks has run)
    var internal_counter = 0;

    for (var i=0; i<total; i++) {
        var request = { '...' : ' ... ' };
        services.search(request, fn_searchCallback);
    }

    // LOCAL Function declaration (which references `internal_counter`)
    function fn_searchCallback(results, status) {
        // Create a local counter for the callbacks
        // I'm showing another way of using a counter: The opposite way
        // Instead of counting the # of finished callbacks, count the number
        //  of *pending* processes. When this counter reaches zero, we're done.
        var local_counter = results.length;
        for (var i=0; i<results.length; i++) {
            service.getDetails(request, fn_detailsCallback);
        }
        // Another LOCAL function (which references `local_counter`)
        function fn_detailsCallback(result, status) {

            // Run the function logic of detailsCallback (from the question)
            // " ... add place marker to maps and assign info window ... "

            // Reduce the counter of pending detailsCallback calls.
            //   If it's zero, all detailsCallbacks has run.
            if (--local_counter === 0) {
                // Increase the "completely finished" counter
                //  and check if we're finished.
                if (++internal_counter === total) {
                    BUILD();
                }
            }
        } // end of fn_detailsCallback
    } // end of fn_searchCallback
}

功能逻辑在评论中解释。我在本节的标题前加上了“复杂”,因为该函数使用嵌套的局部函数和变量。视觉解释:

var types, BUILD;
function search
    var keys, total, internal_counter, fn_searchCallback;
    function fn_searchCallback
        var result, status; // Declared in the formal arguments
        var local_counter, i, fn_detailsCallback;
        function fn_detailsCallback
            var result, status; // Declared in the formal arguments

在上图中,每个缩进级别意味着MDN 上的一个新范围解释。
当一个函数被调用 42 次时,就会创建 42 个新的本地作用域,它们共享同一个父作用域。在作用域内,声明的变量对父作用域不可见。尽管父作用域中的变量可以由“子”作用域中的变量读取和更新,但前提是您未声明具有相同名称的变量。此功能用于我的答案功能。

于 2012-06-30T17:17:44.660 回答
0

我想你已经理解了这一点,但是 BUILD() 在之前的回调函数仍在运行时被线性调用。就像您创建了额外的线程一样。解决该问题的一种方法是使 BUILD 成为搜索函数的回调,其中包含 for 循环。这将保证在调用它之前所有功能都已完成。

这个问题可能有助于实现回调:Create a custom callback in JavaScript

于 2012-06-30T17:19:12.823 回答