AngularJS, обещание с рекурсивной функцией
Я пытаюсь использовать предложение AngularJS/then с рекурсивной функцией. Но тогда функция не вызывается (ни один из вызовов error-, success-, notify-callback не вызван).
Вот мой код:
рекурсивная функция
loadSection2 = function() {
var apiURL = "http://..."
var deferred = $q.defer();
$http({
method: "GET",
url: apiURL
}).success(function(result, status, headers, config) {
console.log(result);
loadCount++;
if(loadCount < 10) {
newSectionArray.push(result);
loadSection2();
} else {
loadCount = 0;
deferred.resolve();
return deferred.promise;
}
}).error(function() {
return deferred.reject();
});
deferred.notify();
return deferred.promise;
};
затем
loadSection2().then(function() {
console.log("NEW SECTIONS LOADED, start adding to document");
addContent();
}, function() {
console.log("ERROR CALLBACK");
}, function() {
console.log("NOTIFY CALLBACK");
}).then(function() {
loadScrollActive = false;
});
Я думаю, что тогда должен получить, по крайней мере, первый ответ-обратный вызов. Но обратного вызова нет.
Не работает ли с рекурсивной функцией?
Ответы
Ответ 1
EDIT - 11/11/2015 Существует гораздо более чистый способ, если вам не нужно уведомлять:
loadSection2 = function (){
var apiURL = "http://..."
return $http.get(apiURL)
.then(function(response){
loadCount++;
if (loadCount < 10) {
newSectionArray.push(response.data);
return loadSection2();
}
loadCount = 0;
});
};
Старый ответ доступен здесь:
Вы можете беспрепятственно выполнять обещание до конца.
loadSection2 = function(deferred) {
if(!deferred){
deferred = $q.defer();
}
var apiURL = "http://..."
$http({
method: "GET",
url: apiURL
}).success(function(result, status, headers, config) {
console.log(result);
loadCount++;
if(loadCount < 10) {
newSectionArray.push(result);
loadSection2(deferred);
} else {
loadCount = 0;
deferred.resolve();
return deferred.promise;
}
}).error(function() {
return deferred.reject();
});
deferred.notify();
return deferred.promise;
};
Ответ 2
Я хотел сделать решение, которое не пропускает "отложенную" переменную, и хотя я бы не сказал, что это лучший подход, он работает, и я узнал от него (jsfiddle).
19/Aug/14. Обновлен код до более короткой версии, удалив создание другого обещания в f1(). Надеюсь, что ясно, как это связано с первоначальным вопросом. Если это не дайте мне знать в комментарии.
f1().then(function() {
console.log("done");
});
function f1(counter) {
if (!counter) {
counter = 0;
}
counter++;
console.log(counter);
return asyncFunc().then(function() {
if (counter < 10) {
return f1(counter);
} else {
return;
}
});
}
function asyncFunc() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve();
}, 100);
return deferred.promise;
}
Ответ 3
Fauphi,
Рекурсия полностью жизнеспособна, но не является особенно "перспективным" подходом.
Учитывая, что у вас есть отложенные / promises доступные, вы можете динамически строить цепочку .then()
, которая обеспечивает обещание заполненного массива.
function loadSection2(arr) {
return $http({
method: "GET",
url: "http://..."
}).then(function(result, status, headers, config) {
console.log(result);
arr.push(result);
return arr;//make the array available to the next call to loadSection2().
}, function() {
console.log("GET error");
return $q.defer().resolve(arr).promise;//allow the chain to continue, despite the error.
//or I think $q .then() allows the much simpler form ...
//return arr; //allow the chain to continue, despite the error.
});
};
var newSectionPromise = $q.defer().resolve([]).promise;//note that the deferred is resolved with an anonymous new array.
//Now we build a .then() chain, ten long, ...
for (var i=0; i<10; i++) {
newSectionPromise = newSectionPromise.then(loadSection2);
}
// ... and do something with the populated array when the GETs have done their thing.
newSectionPromise().then(function(arr) {
console.log(arr.length + " new sections loaded, start adding to document");
addContent(arr);
}, function() {
console.log("ERROR CALLBACK");
}).then(function() {
loadScrollActive = false;
});
непроверенных
То, что было newSectionArray
теперь создано анонимно и передано цепочкой .then()
независимо от успеха/отказа отдельных GET, появившихся как arr
в последнем обработчике успеха. then, где он передается в addContent()
. Это позволяет избежать необходимости в члене newSectionArray
во внешней области.
Немного отредактировав, loadSection2
может быть анонимным, что еще больше уменьшит количество участников, добавленных во внешнюю область.
Необходимость явного уведомления исчезает как:
- уже нет мастера, отложенного для уведомления
-
console.log(result);
в обработчике успеха GET предоставляет все необходимые уведомления.