javascript AngularJS,具有递归函数的承诺

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20607313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 18:52:32  来源:igfitidea点击:

AngularJS, promise with recursive function

javascriptangularjsrecursionpromise

提问by Fauphi

I'm trying to use the AngularJS promise/then with a recursive function. But the then-function is not called (none of the error-, success-, notify-callbacks gets called).

我正在尝试将 AngularJS promise/then 与递归函数一起使用。但是 then 函数没有被调用(错误、成功、通知回调都没有被调用)。

Here is my code:

这是我的代码:

recursive function

递归函数

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

then

然后

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

I think, the then has to get the first notify-callback at least. But there is no callback. Is then not working with recursive function?

我认为,那么至少必须获得第一个通知回调。但是没有回调。那么不使用递归函数吗?

回答by Mathew Berg

EDIT - 11/11/2015There is a much cleaner way if you don't care about notify:

编辑 - 2015 年 11 月 11 日,如果您不关心通知,则有一种更清洁的方法:

loadSection2 = function (){
    var apiURL = "http://..."
    return $http.get(apiURL)
        .then(function(response){
            loadCount++;        
            if (loadCount < 10) {
                newSectionArray.push(response.data);
                return loadSection2();
            }
            loadCount = 0;
        });

};

Old answer available here:

旧答案可在此处获得:

You could continuously pass the promise all the way through.

你可以一直通过这个承诺。

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

回答by VitalyB

I wanted to make a solution that doesn't pass "deferred" variable around and even though I wouldn't say it is a better approach, it works and I learned a from it (jsfiddle).

我想制定一个不传递“延迟”变量的解决方案,尽管我不会说这是一种更好的方法,但它确实有效,而且我从中学到了(jsfiddle)。

19/Aug/14- Updated the code to a much shorter version by removing the creation of another promise in f1(). I hope that it is clear how it relates to the original question. If it isn't let me know in a comment.

2014 年 8 月 19 日- 通过删除 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;
}

回答by Beetroot-Beetroot

Fauphi,

福菲,

Recursion is totally viable but not a particularly "promisy" approach.

递归是完全可行的,但不是一种特别“有前途”的方法。

Given that you have deferreds/promises available, you can dynamically build a .then()chain, which delivers a promise of a populated array.

鉴于您有可用的延迟/承诺,您可以动态构建一个.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's .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;
});

untested

未经测试

What was newSectionArrayis now created anonymously and passed down the .then()chain regardless of success/failure of the individual GETs, emerging as arrin the final .then's success handler, where it is passed to addContent(). This avoids the need for member newSectionArrayin the outer scope.

什么是newSectionArray现匿名的创建和流传下来的.then(),无论成功的连锁/个人的失败入眼,如出现arr在最后。后来的成功处理程序,在那里它被传递给addContent()。这避免了newSectionArray在外部作用域中需要成员。

Rearranging slightly, loadSection2could be made anonymous, further reducing the number of members added to the outer scope.

稍微重新排列,loadSection2可以匿名,进一步减少添加到外部范围的成员数量。

The need for an explicit notification disappears as :

对显式通知的需求消失为:

  • there is no longer a master deferred to be notified
  • console.log(result);in the GET success handler provides all the notification necessary.
  • 不再有推迟通知的主人
  • console.log(result);在 GET 成功处理程序中提供了所有必要的通知。