我有几行项目。每行都有不同数量的项目。 我想要一个计数器来跟踪加载的项目总数。我有一个通过 AJAX 调用递归循环所有行的函数,就像这样(我已经注释掉了与问题无关的内容)
$(document).ready(function () {
var num_loaded = 0;
var row = 0;
load(row, num_loaded);
}
function load(row, num_loaded) {
var count = num_loaded;
$.ajax({
// url and other stuff
// ...
success: function (response) {
for (i = 0; i < response.items.length; i++) {
// load item[i]
// ...
count++;
}
// logic that checks row+1 is not out of bounds
// ...
load(row+1, count);
}
})
console.log(count);
}
如您所见,成功后,每个加载函数都会调用自身并传入一个跟踪计数的参数。这不起作用,我在控制台中不断收到 NaN 或未定义。如何完成此操作并仅查看加载的项目数的最终计数?
最佳答案
您的主要问题是一个相当常见的回调问题,即您将 ajax 视为同步调用,而实际上它是异步的。换句话说,您尝试在调用 ajax
之后立即打印 count
,但到那时 count
不会更新。
var count = num_loaded;
$.ajax({
// ... this updates count some time later
});
// this happens right after we call $.ajax but before the success callback
// so count still has the same value as before we called $.ajax
console.log(count);
这是一个related question你可以看看
此外,您在 load()
方法中定义计数器,这意味着它将在每次函数调用的调用堆栈上重新创建。
如果您通过异步回调递归地传递 count
,则只要递归停止(即达到最大行数的基本情况),它将具有正确的值,因此您必须在回调中打印它:
$(document).ready(function () {
load(0, 0);
}
function load(row, count) {
$.ajax({
// ...
success: function(response) {
// ... loop that increments the count
if ( /* your base case is reached */ ) {
console.log(count);
} else {
load(row + 1, count);
}
}
});
}
}
更干净、更合理的方法是使用 Promise。您可以让 load()
方法返回 Promise这将在成功时:
- 解决加载下一行的 promise ,或者 如果达到基本情况,
- 打印
count
。
由于 Promise 是可链接的,我们也可以轻松地递归传递 count
:
function loadWithPromise(row, count) {
return new Promise(function(resolve) {
$.ajax({
// ...
success: function(response) {
// ... loop that increments the count
// if we reached the base case, resolve this promise (and thus the whole chain)
if ( /* your base case is reached */ ) {
resolve(count);
}
// otherwise load the next promise
else {
resolve(loadWithPromise(row + 1, count));
}
}
});
});
}
// recursively load all rows and then print count once we're done
loadWithPromise(0, 0).then(function(count) {
console.log(count);
});
如果不需要按顺序加载行,可以使用 Promise.all等待所有对 load()
的调用完成,然后再打印count
。这样你就可以将所有的 promise 保存在一个数组中并让它们独立发生,而且你不需要递归。但缺点是您需要在全局范围内定义 count
,因为这些 promise 现在是不相关的:
var count = 0;
function loadWithPromise(row) {
return new Promise(function(resolve) {
$.ajax({
// ...
success: function(response) {
// ... loop that increments the count
resolve();
}
});
});
}
var promises = [];
for (var row = 0; row < MAX_ROWS; row++) {
promises.push(loadWithPromise(row));
}
// once all loading operations have resolved, print the count
Promise.all(promises).then(function() {
console.log(count);
});
关于javascript - 如何在递归 AJAX 调用中保留计数器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39283770/