Подтвердить что ты не робот

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;
});

Я думаю, что тогда должен получить, по крайней мере, первый ответ-обратный вызов. Но обратного вызова нет. Не работает ли с рекурсивной функцией?

4b9b3361

Ответ 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 предоставляет все необходимые уведомления.