У меня есть фрагмент кода jQuery, который быстро вызывает несколько вызовов getJSON():
var table = $("table#output");
for (var i in items) {
var thisItem = items[i];
$.getJSON("myService", { "itemID": thisItem }, function(json) {
var str = "<tr>";
str += "<td>" + thisItem + "</td>";
str += "<td>" + json.someMember + "</td>";
str += "</tr>";
table.append(str);
});
}
Когда я запускаю это на отстающем сервере, таблица заполняется ожидаемыми значениями json.someMember (они поступают не по порядку: я не возражаю), но столбец thisItem заполняется непредсказуемой смесью значений из различных итераций.
Я предполагаю, что это как-то связано с областью действия и временем - функция обратного вызова считывает thisItem из более широкого диапазона? Я прав? Как мне предотвратить это?
Мой текущий обходной путь заключается в том, чтобы служба JSON возвращала копию своих входных данных, что, мягко говоря, неудовлетворительно.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Похоже, проблема с областью видимости из-за петли. Попробуй это:
var table = $("table#output");
for (var i in items) {
var thisItem = items[i];
$.getJSON("myService", { "itemID": thisItem }, (function(thisItem) {
return function(json) {
var str = "<tr>";
str += "<td>" + thisItem + "</td>";
str += "<td>" + json.someMember + "</td>";
str += "</tr>";
table.append(str);
}
})(thisItem));
}
Редактировать: все, что я сделал, это подключил thisItem к обратному вызову $.getJSON.
Я не думаю, что это сработает с jQuery. Разве json не попадет в закрытие вместо переменной thisItem и не вызовет ошибку?
Нет. $ .GetJSON передается внутренней функции; тот, который получает параметр "json".
Похоже, это сработало (после того, как я разобрал все брекеты!). Спасибо!
Спасибо Crescent Fresh, мне пришлось передать индекс для таблицы изображений, которую я хотел заполнить (сгорел из-за асинхронных возвратов, хотя я знал о них, не был уверен, как их охватить). Прохождение индекса сработало как шарм!
Javascript не использует блок для области видимости. Объем основан только на функциях.
Если вам нужна новая область видимости, вы должны объявить новую внутреннюю функцию и немедленно запустить ее, это единственный способ создать новую область видимости в Javascript.
var table = $("table#output");
for( var i in items )
{
(function(){
var thisItem = items[i];
$.getJSON("myService", { "itemID": thisItem }, function(json)
{
var str = "<tr>";
str += "<td>" + thisItem + "</td>";
str += "<td>" + json.someMember + "</td>";
str += "</tr>";
table.append(str);
});
})();
}
Мне нравится это решение, поскольку оно позволяет мне иметь больше локальных переменных, таких как thisItem, без подробной сигнатуры функции.
забавный факт: именно так в Scheme обычно реализуется область видимости.
Я забыл о другом способе, вы можете использовать цикл for из библиотеки, они фактически принимают функцию в качестве блока, выполняемого на каждой итерации. В jQuery: $ .each (items, function (i, item) {...});
Большое спасибо, Винсент. Я горел из-за асинхронных обратных вызовов. инкапсулировал переданный индекс, чтобы знать, куда поместить мои возвраты и whala!
Спасибо, Слим, за этот вопрос. У меня также были некоторые проблемы (я знал о возврате асинхронной функции, но не знал, как сообщить обратному вызову getJSON, в каком месте разместить возвращаемое значение).