Замыкание внутри цикла for - обратный вызов с переменной цикла в качестве параметра

Я использую jQuery "GET" в цикле, чтобы получить несколько результатов с сервера. Я хочу включить индекс цикла в качестве фиксированного параметра для обратного вызова, но он не работает.

(Я последовал совету этой статьи о том, как это сделать.)

Однако значение, которое я получаю при обратном вызове, совсем не то, что я ожидаю - вместо каждого значения индекса цикла оно всегда равно выходному значению индекса.

то есть. фрагмент кода здесь выводит "16" для каждого выполнения обратного вызова. Как мне заставить его напечатать 1, 2, 3... (я понимаю, что порядок может быть другим, это нормально)

В дополнение к приведенному ниже коду я попробовал несколько способов указать функцию обратного вызова, например. function(data, textStatus) { return test(data, textStatus, idx); }, 'text'); и т.п.

Как это должно работать?

function test(data, textStatus, siteNo)
{
    console.log("siteNo=" + siteNo);
}

function loadConfigLists()
{
    var siteReport;
    // retrieve site configuration
    jQuery.get("svGetSiteConfig.php", function(data, textStatus) 
    {
        // retrieve port configuration for all sites
        for (var idx=1; idx<=15; idx++)
        {
            var probeIP = siteConfigArray[idx].siteIP;
            if (probeIP != "" && probeIP != null)
            jQuery.get("svGetPortInfo.php?svSiteIpAddr=" + probeIP+"&s="+idx, 
                    function(data, textStatus) { test(data, textStatus, idx); }, 'text'); 
            else // IP value is blank
                siteConfigArray[idx].portManifest = null;
        }
        }
    }, 'text'); 
}

1 ответ

Решение

Это довольно стандартная проблема с замыканиями. Когда вы делаете это:

function(data, textStatus) { test(data, textStatus, idx); }

Вы связываете ссылку на idx но не к стоимости idx, Таким образом, к тому времени, когда ваш обратный вызов будет вызван, цикл завершится и idx будет 16 во всех обратных вызовов, которые вы связали.

Обычное решение состоит в том, чтобы форсировать оценку idx через вызов функции:

function build_callback(idx) {
    return function(data, textStatus) {
        test(data, textStatus, idx);
    };
}

// And then...

jQuery.get("svGetPortInfo.php?svSiteIpAddr=" + probeIP+"&s="+idx, build_callback(idx), 'text');

Вы также можете встроить функцию в самовыполняющуюся функцию, если хотите сохранить все вместе:

for (var idx=1; idx<=15; idx++)
    (function(idx) {
        var probeIP = siteConfigArray[idx].siteIP;
        if (probeIP != "" && probeIP != null)
            jQuery.get("svGetPortInfo.php?svSiteIpAddr=" + probeIP+"&s="+idx, 
                function(data, textStatus) { test(data, textStatus, idx); }, 'text'); 
        else // IP value is blank
            siteConfigArray[idx].portManifest = null;
    })(idx);

Вызов функции дает вам значение idx когда функция вызывается, и это значение idx что ты хочешь.

Другие вопросы по тегам